ES6之Class

关于 ES6 种新引入的 Class,争执已久,支持和反对的各有一套说辞,但不管怎么说,后来者从来只管用新特性,并不关心这些事儿。殊不知,Class 的背后依然还是 Prototype 原型链结构。

基本语法

ES6引用的 class 语法本质上来说是 JavaScript 中已有创建对象方式及原型链继承的语法糖。下面 ES6 代码中的 Person 类本质上相当于 ES5 中的构造函数 Person()

1
2
3
4
5
6
7
8
class Person {
constructor(name) {
this.name = name;
}
toString() {
return `${this.name}`;
}
}

上面的代码定义了一个 “类”。使用 class 的语法规则如下:

  1. 每一个 class 必须声明一个 constructor 方法,当通过 new 类名生成对象实例时,会自动调用该方法;如果没有显式定义,那么将会默认添加一个空的 constructor 方法
  2. 类内部的方法声明无需使用 function 关键字,且全都被定义在 property 对象上面
  3. 类内部的方法声明之间无需使用逗号分隔
  4. 类内部定义的所有方法都是不可枚举的
  5. 类内部的 this,默认指向类的实例
  6. 使用类创建新的实例对象时,必须使用 new 命令调用类名
  7. class 关键字声明的类在作用域中没有变量提升
  8. 类具有 name 属性,其值为类名

class表达式

我们也可以使用表达式的方式来定义一个类:

1
2
3
4
5
const Person = class Them {
constructor(name) {
this.name = name;
}
};

这种情况下,class 关键字后面的类名只在类的内部有效。当然,如果用不到,我们也可以省去 class 后面的类名,这跟匿名函数表达式相似:

1
2
3
4
5
const Person = class {
constructor(name) {
this.name = name;
}
}

Class的继承

Class之间可以使用 extends 关键字实现继承:

1
2
3
4
5
6
7
8
9
class Student extends Person {
constructor(name, subject) {
super(name);
this.subject = subject;
}
toString() {
return `${super.toString()} ${this.subject}`;
}
}

使用 extends 关键字实现继承时,语法规则如下:

  1. 子类必须在 constructor 方法中调用 super 方法,否则新建实例时会报错,这里的 super 关键字表示的方法为父类的构造函数。子类没有自己的 this 对象,调用 super 方法是为了继承父类的 this 对象
  2. 在子类的 constructor 方法中,只有调用 super 之后才可以使用 this 关键字。这是因为子类实例的构建,是基于对父类实例的加工,只有 super 方法才能返回父类实例

两条继承链

Class作为构造函数的语法糖,同时拥有 prototype 属性和 _proto_ 属性,因此同时存在两条继承连:

  1. 子类的 [[Prototype]] 属性,表示构造函数的继承,总是指向父类
  2. 子类的 prototype 属性的 [[Protoype]] 属性,表示方法的继承,总是指向父类的 prototype 属性

继承目标

extends 关键字后面可以跟多种类型的值:

1
class B extens A {}

上面代码中的 A ,只要是一个有 prototype 属性的函数,就能被 B 继承。

判断继承关系

Object.getPrototypeOf() 方法可以用来获取子类的父类

super关键字

super 关键字有两种用法,含义不同:

  1. 作为函数调用时,super 表示父类的构造函数
  2. 作为对象调用时,super 代表父类。此时,super 既可以引用父类实例的属性和方法,也可引用父类的静态属性和方法。

Class的 getter 和 settter

与 ES5 一样,在 Class 内部可以使用 getset 关键字,对某个属性设置存值函数和取值函数。

Class的 Gernerator 方法

如果在某个方法之前加上 * ,就表示该方法是一个 Generator 函数。

Class的静态方法

静态方法指的是 Class 本身的方法。

在 Class 内部声明的方法之前加上 static 关键字,就可声明一个类的静态方法。只可以使用类名调用。

父类的静态方法可以被子类继承

静态方法也可从 super 对象上调用。

Class的静态属性和实例属性

new.target 属性

ES6 为 new 命令引用了一个 new.taret 属性(在构造函数中),其值为 new 命令作用于的那个构造函数。如果构造函数不是通过 new 调用的,那么将返回 undefined

注意:此属性只能在函数内部使用。


参考