class是语法糖,它背后使用的仍然是原型和构造函数的概念。

定义

  1. // 类声明
  2. class Person {}
  3. // 类表达式
  4. const Animal = class {};

与函数表达式类似,类表达式在它们被求值前也不能引用。
函数声明可以提升,但类定义不能。
函数受函数作用域限制,而类受块作用域限制

constructor

constructor 关键字用于在类定义块内部创建类的构造函数
类实例化时传入的参数会用作构造函数的参数。不需要参数时,括号可省略。

  1. class Person {
  2. constructor(name) {
  3. console.log(arguments.length);
  4. this.name = name || null;
  5. }
  6. }
  7. let p1 = new Person; // 0
  8. console.log(p1.name); // null
  9. let p2 = new Person(); // 0
  10. console.log(p2.name); // null
  11. let p3 = new Person('Jake'); // 1
  12. console.log(p3.name); // Jake

类构造函数与构造函数的主要区别是,调用类构造函数必须使用new 操作符。而普通构造函数如果不使用 new 调用,那么就会以全局的 this (通常是 window )作为内部对象。

类是一种特殊函数

  1. typeof Person // function

与立即调用函数表达式相似,类也可以立即实例化:

  1. // 因为是一个类表达式,所以类名是可选的
  2. let p = new class Foo {
  3. constructor(x) {
  4. console.log(x);
  5. }
  6. }('bar'); // bar
  7. console.log(p); // Foo {}

constructor内定义的属性和方法都在实例

  1. class Person {
  2. constructor() {
  3. this.name = new String('Jack');
  4. this.sayName = () =>
  5. console.log(this.name);
  6. this.nicknames = ['Jake', 'J-Dog']
  7. }
  8. }
  9. let p1 = new Person()

原型

在constructor外,class内,,可以为prototype定义method,但不能定义property

  1. class Person {
  2. constructor() {
  3. // 添加到this的所有内容都会存在于不同的实例上
  4. this.locate = () =>
  5. console.log('instance');
  6. }
  7. // 在类块中定义的所有内容都会定义在类的原型上
  8. locate() {
  9. console.log('prototype');
  10. }
  11. }
  12. let p = new Person();
  13. p.locate(); // instance
  14. Person.prototype.locate(); // prototype

在class之外可以定义实例和原型属性

  1. class Person {
  2. sayName() {
  3. console.log('${Person.greeting} ${this.name}');
  4. }
  5. }
  6. // Define data member on class
  7. Person.greeting = 'My name is';
  8. // Define data member on prototype
  9. Person.prototype.name = 'Jake';
  10. let p = new Person();
  11. p.sayName(); // My name is Jake

getter/setter

  1. class Person {
  2. set name(newName) {
  3. this.name_ = newName;
  4. }
  5. get name() {
  6. return this.name_;
  7. }
  8. }
  9. let p = new Person();
  10. p.name = 'Jake';
  11. console.log(p.name); // Jake

静态类方法

定义在class上的方法,this指向class, 关键字static

  1. class Person {
  2. constructor() {
  3. // Everything added to 'this' will exist on each individual instance
  4. this.locate = () => console.log('instance', this);
  5. }
  6. // Defined on the class prototype object
  7. locate() {
  8. console.log('prototype', this);
  9. }
  10. // Defined on the class
  11. static locate() {
  12. console.log('class', this);
  13. }
  14. }
  15. let p = new Person();
  16. p.locate(); // instance, Person {}
  17. Person.prototype.locate(); // prototype, {constructor: ... }
  18. Person.locate(); // class, class Person {}

Inheritance

Although it makes use of a new syntax, class inheritance still uses the prototype chain under the hood.
使用 extends 关键字,就可以继承任何拥有 [[Construct]] 和原型的对象(包括函数);

  1. class Vehicle {}
  2. // Inherit from class
  3. class Bus extends Vehicle {}
  4. let b = new Bus();
  5. console.log(b instanceof Bus); // true
  6. console.log(b instanceof Vehicle); // true
  7. function Person() {}
  8. // Inherit from function constructor
  9. class Engineer extends Person {}
  10. let e = new Engineer();
  11. console.log(e instanceof Engineer); // true
  12. console.log(e instanceof Person); // true

super()

super用于派生类调用父类的构造函数,在派生的类中, 在你可以使用’this‘之前, 必须先调用super()
super也可以用于静态方法。
如果父类的构造函数传了参数,super也要传相同的参数。
如果在派生类中显式定义了构造函数,则要么必须在其中调用 super() ,要么必须在其中返回一个对象。

  1. class Vehicle {
  2. constructor() {
  3. this.hasEngine = true;
  4. }
  5. }
  6. class Bus extends Vehicle {
  7. constructor() {
  8. // Cannot reference 'this' before super(), will throw ReferenceError
  9. super(); // same as super.constructor()
  10. console.log(this instanceof Vehicle); // true
  11. console.log(this); // Bus { hasEngine: true }
  12. }
  13. }
  14. new Bus();

抽象基类

抽象基类只能被继承,不能被实例化,通过new.target判断

  1. / 抽象基类
  2. class Vehicle {
  3. constructor() {
  4. if (new.target === Vehicle) {
  5. throw new Error('Vehicle cannot be directly instantiated');
  6. }
  7. if (!this.foo) {
  8. throw new Error('Inheriting class must define foo()');
  9. }
  10. console.log('success!');
  11. }
  12. }
  13. // 派生类
  14. class Bus extends Vehicle {
  15. foo() {}
  16. }
  17. // 派生类
  18. class Van extends Vehicle {}
  19. new Bus(); // success!
  20. new Van(); // Error: Inheriting class must define foo()