ECMAScript 6中类继承解析(附示例)
类继承
看类继承前,先回顾构造函数怎么实现对象的继承的
function F() { this.a = 1; } function Son() { F.call(this); } function inherit(S, F) { S.prototype = Object.create(F.prototype); S.prototype.constructor = S; } inherit(Son, F); let son = new Son();
它实现了哪几个功能:
继承F的this属性也就是F实例对象的属性
Son.prototype.__proto__ === F.prototype 实现了上下辈分的继承
son.constructor让son认祖归宗
同样类继承也是如此
用来extends和super关键字,看一个简单的继承
class A { constructor() { this.a = 1; } } class B extends A { constructor() { super(); this.b = 2; } m() { } } let b = new B();
同样实现了那三点基本功能
B {a: 1, b: 2} b.__proto__ == B.prototype b.__proto__.__proto__ === A.prototype b.constructor === B
我认为:关键字extends实现了原型的继承,以及constructor的修正;关键字super实现了父类this的继承,这里的super相当于A.prototype.constructor.call(this)
注意点
写了constructor,就必须在里面写super,不然new子类实例对象会报错;要么都不写;其次子类的中constructor中的this属性必须写在super后面
1.ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6
的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this
2.因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实 例属性和方法。如果不调用super方法,子类就得不到this对象。
class B extends A { constructor() { //要么都不写,new时默认会自动生成 super(); this.b = 2; //写在super后面 } m() { } }
super的各种指向问题
super作为函数,只能放在子类的constructor中,指向A.prototype.constructor.call(this)
super作为对象,在子类普通方法中调用,super就是父类的原型也就是A.prototype
;所以只能调用原型链上的方法,不能动用父类实例的方法和属性constructor{}
中的不能调用
class A { constructor() { this.a = 1; } n() { return this; } } class B extends A { constructor() { super(); this.b = 2; } m() { return super.n(); } } let b = new B(); b === b.m();
并且规定
在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例。
所以上面return this 就是返回子类实例对象
super作为对象对属性赋值时
super相当于this,赋值属性也就成了子类实例的属性
class A { constructor() { this.x = 1; } } class B extends A { constructor() { super(); this.x = 2; super.x = 3; console.log(super.x); // undefined console.log(this.x); // 3 console.log(super.valueOf() instanceof B); //true } } let b = new B();
super作为对象,在静态方法中指向的是父类能调用父类的静态方法,如果方法内部有this则指向当前的子类
只有类才能调用类的静态方法
class A { constructor() { this.a = 1; } static n() { return this; } } class B extends A { constructor() { super(); this.b = 2; } static m() { return super.n(); } } console.log(A.n() === A) // true console.log(B === B.m()); //true由于对象总是继承其他对象的,所以可以在任意一个对象中,使用super关键字。
var obj = { toString() { return "MyObject: " + super.toString(); } }; Object.getPrototypeOf(obj).toString = function () { return "这里super等于obj.__proto__"; } console.log(obj.toString()); //MyObject: 这里super等于obj.__proto__
类的prototype与__proto__
(1)子类的__proto__属性,表示构造函数的继承,总是指向父类。(2)子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。
类的继承模式
class A { } class B { } // B 的实例继承 A 的实例 Object.setPrototypeOf(B.prototype, A.prototype); // B 继承 A 的静态属性 Object.setPrototypeOf(B, A); const b = new B();
也是因为这种实现所以类能调用自己的静态方法
es6实现了原始构造函数的继承
之前Array.apply(this)this并不会塑造Array里面的内部结构,所以我们当我们用类数组对象引用数组方法时用null代替了
而es6用类实现它的继承,
代码摘自es6入门
class MyArray extends Array { constructor(...args) { super(...args); } } var arr = new MyArray(); arr[0] = 12; arr.length // 1 arr.length = 0; arr[0] // undefined
需要注意的是
ES6 改变了Object构造函数的行为,一旦发现Object方法不是通过new Object()这种形式调用,ES6 规定Object构造函数会忽略参数。
class NewObj extends Object{ constructor(){ super(...arguments); } } var o = new NewObj({attr: true}); o.attr === true // false
传入参数会无效的
以上就是ECMAScript 6中类继承解析(附示例)的详细内容,更多请关注其它相关文章!
下一篇: php怎么让变量称为全局变量