1. class
Class 可以通过 extends 关键字实现继承,这比ES5的通过修改原型链实现继承,要清晰和方便很多
class Point { constructor(x,y){ this.x = x; this.y = y; }
toString() {
console.log('此处是父类的方法')
} }
//class extends 继承 class ColorPoint extends Point { constructor(x,y,color) { super(x,y); // 调用父类的constructor(x,y) 必须 this.color = color; // 子类自己的属性color } myGrade() { // 子类中定义新的myGrade方法 return this.color + super.toString(); // 调用父类的toString() } }
上面代码中,constructor方法和toString方法中,都出现了super关键字,它在这里表示父类的构造函数,用来新建父类的this对象
子类必须在constructor方法中调用super方法,否则新建实例会报错。这是因为子类自己的this 对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例方法和属性,然后再对其进行加工,加上子类自己的实例属性和方法。 如果不调用super方法,子类就得不到this对象 。
上面代码中,ColorPoint 继承父类Point , 但是它的都早函数没有调用super方法,导致新建实例报错
ES5的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this)). ES6的继承机制完成不同,实质是先将父类实例对象的属性和方法,加到this上面(所以不洗先调用super方法),然后再用子类的构造函数修改this
另外一个需要注意的地方是, 在子类的构造函数中,只有调用super后,才可以使用this关键字,否则会报错。 这是因为子类实例的构建,基于父类实例,只有super方法才能调用父类实例
下面是生成子类实例的代码
let cp = new ColorPoint(25,8, 'green'); cp instanceof ColorPoint //true cp instanceof Point // true
上面代码中,实例对象cp 同时是ColorPoint 和 Point 两个类的实例,这与ES5的行为完全一致。
最后,父类的静态方法,也会被子类继承。
class C { constructor(x){ this.x = x } static hello() { console.log('hello world') } } class D extends C { constructor(x) { super(x) // 此时super作为函数,只能用在constructor中 } toString() { console.log(super.hello()) // 此时super作为对象 调用hello } } D.hello(); // hello world const d = new D() console.log(d); d.hello(); // d.hello is not a function 这个问题有待考究
2. Object.getPrototypeOf()
Object.getPrototypeOf 方法可以用来从子类获取父类
Object.getPrototype(ColorPoint) === Point
因此,可以使用这个方法判断,一个类是否继承了另一个类
3. super关键字
super 这个关键字,既可以当做函数使用,也可以当作对象使用。
1) 作为函数调用时
代表父类的构造函数。 ES6要求,子类的构造函数必须执行一次super函数
class A {}
class B extends A {
constructor() {
super()
}
}
上面代码中,子类B的构造函数之中的super(), 代表调用父类的构造函数,这是必须的,否则js会报错
super 虽然代表了父类A的构造函数,但是返回的是子类B的实例, 即super内部的this指的是B的实例。
作为函数时,super() 只能在子类的构造函数中,用在其他地方会报错
class A {} class B extends A { m() { super(); // 报错 } }
2) super作为对象
super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类
class A { p() { return 2; } } class B extends A { constructor() { super(); console.log(super.p()); // 2 } } let b = new B();
上面代码中,子类B当中的super.p(), 就是将super 当作一个对象使用,这时,super在普通方法之中,指向A.prototype, 所有super.p() 就相当于A.prototype.p()
这里需要注意,由于super指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super调用的
class A { constructor() { this.p = 2; } } class B extends A { get m() { return super.p; } } let b = new B(); b.m; // undefined
ES6规定,在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例。
class E { constrcutor(){ this.x = 1 } print() { console.log(this.x) } } class F extends E { constructor() { super(); this.x = 2; // 方法内部的this指向子类的实例 } m() { super.print() } } const f = new F() f.m(); // 2
浙公网安备 33010602011771号