ホームページ  >  記事  >  ウェブフロントエンド  >  jsとtypescriptでのクラスの使い方を詳しく解説

jsとtypescriptでのクラスの使い方を詳しく解説

php中世界最好的语言
php中世界最好的语言オリジナル
2018-04-27 11:43:572102ブラウズ

今回は、js と typescript でのクラスの使用について詳しく説明します。js と typescript でクラスを使用する際の 注意事項 について、実際のケースを見てみましょう。

前書き

JavaScript は関数型プログラミングであり、クラスや new の痕跡はほとんどないため、フロントエンド開発者にとってクラスはほとんど使用されません。したがって、デザインパターンは、ほとんどのフロントエンド開発者の欠点でもあります。

最近、Angular を学習する過程で、Angular が本当に深く研究する価値のある優れたフレームワークであることに気づきました。

この記事では、JavaScript と TypeScript のクラスについて簡単に紹介します。

基本概念

クラスを紹介する前に、最初にいくつかの基本概念を紹介する必要があります。

1. 静的メンバー

クラス自体のメンバーは継承できますが、インスタンスにはアクセスできません。jQuery 時代の最も一般的な $.ajax などの静的メソッドです。使い方は簡単で、new または関数呼び出しを通じて新しいインスタンスを取得する必要はありません。

2. プライベート メンバー

クラス内のメンバーは通常、継承できず、内部でのみ使用できます。これらはクロージャ内の変数に似ていますが、現時点では JavaScript では直接アクセスできません。プライベート メンバーは他の手段でのみ実装できます。

3. Getter/setter

Accessor プロパティ。インスタンスのプロパティにアクセスまたは変更する場合、Vue はデータの変更を追跡するためにこれらの 2 つの操作を実行します。 。

4. インスタンス メンバー

は、new によって作成されたインスタンスのメンバーを指します。この機能により、コードの再利用も可能になります。

5. 抽象クラス、抽象メソッド

抽象クラスはインスタンス化できないクラスを指し、通常は親クラスとして設計されています。

抽象メソッドはメソッドの名前、パラメータ、戻り値を提供するだけであり、特定の実装はサブクラスによって完了されます。サブクラスはすべての抽象メソッドを実装する必要があります。そうでない場合は、エラーが報告されます。

これらの概念はどちらも JavaScript で直接実装することはできませんが、TypeScript または他の

オブジェクト指向 言語では簡単に実装できます。また、この機能はポリモーフィズムを実現するための重要な手段でもあります。

ケース紹介

クラスをよりよく紹介するために、この記事では 3 つのクラス、つまり パーソン、中国人、アメリカ人を例として使用します。単語からすぐにわかります。人は親クラス (基本クラス)、中国人とアメリカ人はサブクラス (派生クラス) です。

person には、名前、年齢、性別、sayHello メソッド、および fullName アクセサー属性の 3 つの属性があります。同時に、Person にはいくつかの静的メンバーとプライベート メンバーもあります。例を考えるのは非常に難しいので、代わりに foo、bar、x、y、z を使用します。

中国人とアメリカ人は、サブクラスとして、Person のインスタンス メンバーと静的メンバーを継承します。同時に、彼らは独自のメソッドと属性もいくつか持っています:

中国人はカンフーの属性を持っており、武道を練習することができます。

アメリカ人はツイッターを持っており、ツイッターを送信することもできます。

次に、JavaScript と TypeScript を使用してこのケースを実装します。

JavaScript のクラス

JavaScript のクラスには、class と extends という 2 つのキーワードが用意されていますが、これらは単なる構文糖ですが、最下層は継承を実装するためにプロトタイプを使用しますが、確かにそれはできません。この方法で記述すると、コードがより明確になり、読みやすくなります。 ES6 より前の class

class Person {
 // #x = '私有属性x';
 // static x = '静态属性x';
 // name;
 // age;
 // gender;
 // 上面的写法还在提案中,并没有成为正式标准,不过变化的可能性已经不大了。
 // 顺便吐槽一下,用 # 表示私有成员,真的是很无语.
 /**
  * Person的静态方法,可以被子类继承
  * 可以通过 this 访问静态成员
  */
 static foo() {
  console.log(`类 ${this.name} 有一个 ${this.x}`);
 }
 constructor(name, age, gender) {
  this.name = name;
  this.age = age;
  this.gender = gender;
 }
 /**
  * 数据存储器,可以访问实例成员,子类的实例可以继承
  * 以通过 this 访问实例成员
  */
 get fullName() {
  const suffix = this.gender === '男' ? '先生' : '女士';
  return this.name + suffix;
 }
 set fullName(value) {
  console.log(`你已改名为 ${value} `);
 }
 /**
  * Person的实例方法,可以被子类的实例继承
  * 可以通过 this 访问实例成员
  */
 sayHello() {
  console.log(`你好我是 ${this.fullName} ,我 ${this.age} 岁了`);
 }
}
Person.x = '静态属性x';
class Chinese extends Person {
 static bar() {
  console.log(`类 ${this.name} 的父类是 ${super.name}`);
  super.foo();
 }
 constructor(name, age, gender, kungfu) {
  super(name, age, gender);
  this.kungfu = kungfu;
 }
 martial() {
  console.log(`${this.name} 正在修炼 ${this.kungfu} `);
 }
}
class American extends Person {
 // static y = '静态属性y';
 static bar() {
  console.log(`类 ${this.name} 有自己的 ${this.y} ,还继承了父类 ${super.name} 的 ${super.x}`);
 }
 constructor(name, age, gender, twitter) {
  super(name, age, gender);
  this.twitter = twitter;
 }
 sendTwitter(msg) {
  console.log(`${this.name} : `);
  console.log(` ${msg}`);
 }
}
American.y = '静态属性y';
Person.x;  // 静态属性x
Person.foo(); // 类 Person 有一个 静态属性x
Chinese.x;  // 静态属性x
Chinese.foo(); // 类 Chinese 有一个 静态属性x
Chinese.bar(); // 类 Chinese 的父类是 Person
American.x;  // 静态属性x
American.y;  // '静态属性y
American.foo(); // 类 American 有一个 静态属性x
American.bar(); // 类 American 有自己的 静态属性y ,还继承了父类 Person 的 静态属性x
const p = new Person('Lucy', 20, '女');
const c = new Chinese('韩梅梅', 18, '女', '咏春拳');
const a = new American('特朗普', 72, '男', 'Donald J. Trump');
c.sayHello(); // 你好我是 韩梅梅女士 ,我 18 岁了
c.martial(); // 韩梅梅 正在修炼 咏春拳 
a.sayHello(); // 你好我是 特朗普先生 ,我 72 岁了
a.sendTwitter('推特治国'); // 特朗普 : 推特治国

class

ES5 における class

ES6 の継承は、基本的に最初にサブクラスのインスタンス オブジェクトを作成することです

然后再将父类的方法添加到 this 上面 Parent.apply(this) 。

ES6 的继承机制完全不同,实质是先创造父类的实例对象 this,所以必须先调用 super 方法,

然后再用子类的构造函数修改this。

为了实现继承,我们需要先实现一个 extendsClass 函数,它的作用是让子类继承父类的静态成员和实例成员。

function extendsClass(parent, child) {
 // 防止子类和父类相同名称的成员被父类覆盖
 var flag = false;
 // 继承静态成员
 for (var k in parent) {
  flag = k in child;
  if (!flag) {
   child[k] = parent[k];
  }
 }
 // 继承父类prototype上的成员
 // 用一个新的构造函数切断父类和子类之间的数据共享
 var F = function () { }
 F.prototype = parent.prototype;
 var o = new F();
 for (var k in o) {
  flag = k in child.prototype;
  if (!flag) {
   child.prototype[k] = o[k];
  }
 }
}
function Person(name, age, gender) {
 this.name = name;
 this.age = age;
 this.gender = this.gender;
 // 如果将 getter/setter 写在 prototype 会获取不到
 Object.defineProperty(this, 'fullName', {
  get: function () {
   var suffix = this.gender === '男' ? '先生' : '女士';
   return this.name + suffix;
  },
  set: function () {
   console.log('你已改名为 ' + value + ' ');
  },
 });
}
Person.x = '静态属性x';
Person.foo = function () {
 console.log('类 ' + this.name + ' 有一个 ' + this.x);
}
Person.prototype = {
 constructor: Person,
 // get fullName() { },
 // set fullName(value) { },
 sayHello: function () {
  console.log('你好我是 ' + this.fullName + ' ,我 ' + this.age + ' 了');
 },
};
function Chinese(name, age, gender, kungfu) {
 // 用call改变this指向,实现继承父类的实例属性
 Person.call(this, name, age, gender);
 this.kungfu = kungfu;
}
Chinese.bar = function () {
 console.log('类 ' + this.name + ' 的父类是 ' + Person.name);
 Person.foo();
}
Chinese.prototype = {
 constructor: Chinese,
 martial: function () {
  console.log(this.name + ' 正在修炼 ' + this.kungfu + ' ');
 }
};
extendsClass(Person, Chinese);
function American(name, age, gender, twitter) {
 Person.call(this, name, age, gender);
 this.twitter = twitter;
}
American.y = '静态属性y';
American.bar = function () {
 console.log('类 ' + this.name + ' 有自己的 ' + this.y + ' ,还继承了父类 ' + Person.name + ' 的 ' + Person.x);
}
American.prototype = {
 constructor: American,
 sendTwitter: function (msg) {
  console.log(this.name + ' : ');
  console.log(' ' + msg);
 }
};
extendsClass(Person, American);

TypeScript 中的 class

讲完了 JavaScript 中的类,还是没有用到 抽象类,抽象方法,私有方法这三个概念,由于 JavaScript 语言的局限性,想要实现这三种概念是很困难的,但是在 TypeScript 可以轻松的实现这一特性。

首先我们稍微修改一下例子中的描述,Person 是抽象类,因为一个正常的人肯定是有国籍的,Person 的 sayHello 方法是抽象方法,因为每个国家打招呼的方式不一样。另外一个人的性别是只能读取,不能修改的,且是确定的是,不是男生就是女生,所以还要借助一下枚举。

enum Gender {
 female = 0,
 male = 1
};
abstract class Person {
 private x: string = '私有属性x,子类和实例都无法访问';
 protected y: string = '私有属性y,子类可以访问,实例无法访问';
 name: string;
 public age: number;
 public readonly gender: Gender; // 用关键字 readonly 表明这是一个只读属性
 public static x: string = '静态属性x';
 public static foo() {
  console.log(`类 ${this.name} 有一个 ${this.x}`);
 }
 constructor(name: string, age: number, gender: Gender) {
  this.name = name;
  this.age = age;
  this.gender = gender;
 }
 get fullName(): string {
  const suffix = this.gender === 1 ? '先生' : '女士';
  return this.name + suffix;
 }
 set FullName(value: string) {
  console.log(`你已改名为 ${value} `);
 }
 // 抽象方法,具体实现交由子类完成
 abstract sayHello(): void;
}
class Chinese extends Person {
 public kungfu: string;
 public static bar() {
  console.log(`类 ${this.name} 的父类是 ${super.name}`);
  super.foo();
 }
 public constructor(name: string, age: number, gender: Gender, kungfu: string) {
  super(name, age, gender);
  this.kungfu = kungfu;
 }
 public sayHello(): void {
  console.log(`你好我是 ${this.fullName} ,我 ${this.age} 岁了`);
 }
 public martial() {
  console.log(`${this.name} 正在修炼 ${this.kungfu} `);
 }
}
class American extends Person {
 static y = '静态属性y';
 public static bar() {
  console.log(`类 ${this.name} 有自己的 ${this.y} ,还继承了父类 ${super.name} 的 ${super.x}`);
 }
 public twitter: string;
 public constructor(name: string, age: number, gender: Gender, twitter: string) {
  super(name, age, gender);
  this.twitter = twitter;
 }
 public sayHello(): void {
  console.log(`Hello, I am ${this.fullName} , I'm ${this.age} years old`);
 }
 public sendTwitter(msg: string): void {
  console.log(`${this.name} : `);
  console.log(` ${msg}`);
 }
}
Person.x;  // 静态属性x
Person.foo(); // 类 Person 有一个 静态属性x
Chinese.x;  // 静态属性x
Chinese.foo(); // 类 Chinese 有一个 静态属性x
Chinese.bar(); // 类 Chinese 的父类是 Person
American.x;  // 静态属性x
American.y;  // '静态属性y
American.foo(); // 类 American 有一个 静态属性x
American.bar(); // 类 American 有自己的 静态属性y ,还继承了父类 Person 的 静态属性x
const c: Chinese = new Chinese('韩梅梅', 18, Gender.female, '咏春拳');
const a: American = new American('特朗普', 72, Gender.male, 'Donald J. Trump');
c.sayHello(); // 你好我是 韩梅梅女士 ,我 18 岁了
c.martial(); // 韩梅梅 正在修炼 咏春拳 
a.sayHello(); // Hello, I am 特朗普先生 , I'm 72 years old
a.sendTwitter('推特治国'); // 特朗普 : 推特治国

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

JS变量声明var,let.const使用详解

Vue组件实现简单弹窗功能案例详解

以上がjsとtypescriptでのクラスの使い方を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。