2021.05.26(Class 的继承)
Class 可以通过 extends 关键字实现继承,这比 ES5 的通过修改原型链实现继承,要清晰和方便
很多。
1. class Point { 2. } 3. 4. class ColorPoint extends Point { 5. }
上面代码定义了一个 ColorPoint 类,该类通过 extends 关键字,继承了 Point 类的所有属性
和方法。但是由于没有部署任何代码,所以这两个类完全一样,等于复制了一个 Point 类。下面,我
们在 ColorPoint 内部加上代码。
1. class ColorPoint extends Point { 2. constructor(x, y, color) { 3. super(x, y); // 调用父类的constructor(x, y) 4. this.color = color; 5. } 6. 7. toString() { 8. return this.color + ' ' + super.toString(); // 调用父类的toString() 9. } 10. }
上面代码中, constructor 方法和 toString 方法之中,都出现了 super 关键字,它在这里表
示父类的构造函数,用来新建父类的 this 对象。
子类必须在 constructor 方法中调用 super 方法,否则新建实例时会报错。这是因为子类自己
的 this 对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对
其进行加工,加上子类自己的实例属性和方法。如果不调用 super 方法,子类就得不到 this 对
象。
1. class Point { /* ... */ } 2. 3. class ColorPoint extends Point { 4. constructor() { 5. } 6. } 7. 8. let cp = new ColorPoint(); // ReferenceError
上面代码中, ColorPoint 继承了父类 Point ,但是它的构造函数没有调用 super 方法,导致
新建实例时报错。
ES5 的继承,实质是先创造子类的实例对象 this ,然后再将父类的方法添加到 this 上面
( Parent.apply(this) )。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,
加到 this 上面(所以必须先调用 super 方法),然后再用子类的构造函数修改 this 。
如果子类没有定义 constructor 方法,这个方法会被默认添加,代码如下。也就是说,不管有没有
显式定义,任何一个子类都有 constructor 方法。
1. class ColorPoint extends Point { 2. } 3. 4. // 等同于 5. class ColorPoint extends Point { 6. constructor(...args) { 7. super(...args); 8. } 9. }
另一个需要注意的地方是,在子类的构造函数中,只有调用 super 之后,才可以使用 this 关键
字,否则会报错。这是因为子类实例的构建,基于父类实例,只有 super 方法才能调用父类实例。
1. class Point { 2. constructor(x, y) { 3. this.x = x; 4. this.y = y; 5. } 6. } 7. 8. class ColorPoint extends Point { 9. constructor(x, y, color) { 10. this.color = color; // ReferenceError 11. super(x, y); 12. this.color = color; // 正确 13. } 14. }
上面代码中,子类的 constructor 方法没有调用 super 之前,就使用 this 关键字,结果报错,而放在 super 方法之后就是正确的。
2021-05-28 17:22:32