我看书上说ES6之前的js无法真正实现内建对象的继承,但原因不是很明白,例如内建数组Array对象的继承:
function MyArray() {
Array.apply(this, arguments)
}
MyArray.prototype = Object.create(Array.prototype, {
constructor: {
value: MyArray,
writable: true,
configurable: true,
enumerable: true
}
})
const arr = new MyArray()
arr1 = new Array();
arr[0] = 'a'; arr1[0] = 'a'
console.log(arr[0], arr1[0]); // a a
arr.length = 0; arr1.length = 0;
console.log(arr[0], arr1[0]); // a undefined 和原生的产生了差异,没有实现真正的继承
但为什么会出现这样的差异呢,书上的解释:
在ECMAScript 5的传统继承方式中,先由派生类型(例如,MyArray)创建this的值,然后调用基类型的构造函数(例如Array.apply()方法)。这也意味着,this的值开始指向的是MyArray的实例,但是随后会被来自Array的其他属性所修饰。ECMAScript 6中的类继承则与之相反,先由基类(Array)创建this的值,然后派生类的构造函数(MyArray)再修改这个值。所以一开始可以通过this访问基类的所有内建功能,然后再正确地接收所有与之相关的功能。
不是很明白,在我的理解,继承就是将父类实例中的属性(也就是this.属性名)拷贝到子类实例中,然后让子类的原型指向父类的原型,继承原型的方法,这样子类就可以使用所有子类可以使用的,这样说的话上面的写法已经实现了继承,能解释一下为什么没有实现真正的继承吗?
具体原因是因为你在用 ES5 模拟 ES6 继承的时候,实例对象是先通过子类构造函数产生,也就是先 new 进行子类实例化,然后再通过父类构造函数构造。
而真正的 ES6 类继承,实例对象是通过父类构造函数产生,也就是说 new 要先调用 super() 进行父类实例化,然后再通过子类构造函数构造。
两者的区别在于实例对象的真正起源不同、构造过程的时序和具体实例的行为表现不同。