阮一峰ES6 Class继承
(1)简介
①Class通过extends实现继承。
②子类必须在constructor方法中调用super方法,否则新建实例时会报错;
因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,
然后对其进行加工,加上子类自己的实例属性和方法,如果不调用super方法,子类就得不到this对象。
【注意:在子类的构造函数中,只有先调用super之后,才可以使用this关键字,否则报错】
③ES5的继承和ES6的继承的区别:
ES5的继承实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面。
ES6的继承机制不同,实质上是现将父类实例对象的属性和方法,加到this上面(所以需要先调用super方法),
然后再调用子类的构造函数修改this。
如果子类没有定义constructor方法,这个方法会被默认添。
④父类的静态方法,也会被子类继承。
(2)Object.getPrototypeOf()
判断一个类是否继承了另一个类
Object.getPrototypeof(B)===A 判断B是否继承自A
(3)super关键字
super关键字既可以当做函数使用,也可以当做对象使用。
①super当做函数调用,代表父类的构造函数。
【注意super虽然代表父类的构造函数,但返回的是子类的实例,即super内部的this指向子类的实例。】
作为函数时,super()只能用在子类的构造函数之中,用在其他地方会报错
②super作为对象时,在普通方法中,指向父类的原型对象(不是父类的实例);在静态方法中,指向父类。
【注:super指向父类的原型对象,只能访问定义在父类原型对象(proptype)上的方法或属性,想访问父类实例上的方法
或属性则无法通过super调用】
ES6规定,在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前子类的实例。
在子类的静态方法中通过super调用父类方法时,方法内部的this指向当前的子类。
【注意:使用super的时候,必须显式指定是作为函数还是作为对象使用,否则会报错】
由于对象总是继承其他对象的,所以可以在任意一个对象中使用super关键字。
(4)类的prototype属性和__proto__属性
ES5中,每个对象都有__proto__属性,指向对应构造函数的prototype属性。
Class作为构造函数的语法糖,同时又prototype和__proto属性,因此有两条继承链。
①子类的__proto__属性,表示构造函数的继承,总是指向父类
即:B.__proto__===A(假设B类继承自A类)
②子类的prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性
即:B.prototype.__proto__===A.prototype
extends关键字后面可以跟多种类型的值
class B extends A{
}
A只要有prototype属性的函数,就能被B继承,由于函数都有prototype属性(除了Function.prototype函数),
因此A可以是任意函数。
下面讨论两种特殊情况:
①子类继承Object类
class A extends Object {
}
A.__proto__ === Object // true
A.prototype.__proto__ === Object.prototype // true
这种情况下,A其实就是构造函数Object的复制,A的实例就是Object的实例。
②不存在任何继承
class A {
}
A.__proto__ === Function.prototype // true
A.prototype.__proto__ === Object.prototype // true
这种情况下,A作为一个基类(即不存在任何继承),就是一个普通函数,所以直接继承Function.prototype。但是,A调用后返回一个空对象(即Object实例),
所以A.prototype.__proto__指向构造函数(Object)的prototype属性。
实例的__proto__属性
前面我们知道了B.prototype.__proto__===A.prototype
以及ES5中实例对象的__proto__执行构造函数的prototype
所以b.__proto.__proto=a.__proto__
因此,通过子类实例的__proto__.__proto__属性,可以修改父类实例的行为。
(5)原生构造函数的继承
原生构造函数是值语言内置的构造函数,通常用来生成数据结构:
原生构造函数包含:
Boolean()
Number()
String()
Array()
Date()
Function()
RegExp()
Error()
Object()
ES5中,这些元素构造函数是无法继承的。ES6允许继承元素构造函数定义子类。
因为ES5是先新建子类的实例对象this,再将父类的属性添加到子类上,由于父类的内部属性无法
获取,导致无法继承原生的构造函数。
ES6语序继承原生构造函数定义子类,因为 ES6 是先新建父类的实例对象this,
然后再用子类的构造函数修饰this,使得父类的所有行为都可以继承。
(6)Mixin模式的实现
Mixin 指的是多个对象合成一个新的对象,新对象具有各个组成成员的接口。
更多内容,参见源文档