ES6 浅谈class继承机制
2019-03-21 本文已影响0人
宋乐怡
文章来源阮一峰ES6入门,这里做要点掌握大纲。
class——构造函数的语法糖
ES5的继承:修改原型链
先创造子类的实例对象,再将父类的方法添加到this(Parent.apply(this) )
ES6的继承:通过extends实现继承
先将父类实例 的属性方法加到this上(super),然后再用子类的构造函数修改this
- super
- 子类必须在构造函数中调用super方法,用来创建父类的this对象。因为子类this通过父类构造函数塑造,得到和父类一样的实例属性和方法(实例属性和类的本身属性参考上一节class的基本语法。)不调用super,子类就得不到this。
在子类的构造函数中,只有调用super之后才可以使用this 关键字,因为super 之后子类才有了自己的this。 - super关键字可以当函数使用也可以当对象使用。用法不同。必须显示指定super的数据类型
class A {}
class B extends A {
constructor() {
super();
console.log(super.valueOf() instanceof B); // true,valueOf()返回该对象的原始值。
}
}
let b = new B();
作为函数使用时,代表父类的构造函数,只能在子类构造函数中使用,super内部的this指向子类实例。
class A {
constructor() {
console.log(new.target.name);
}
}
class B extends A {
constructor() {
super();
}
}
new A() // A
new B() // B
作为对象使用时,在静态方法中指向父类,在普通方法中,指向父类原型对象。
注意:super指向父类的原型对象,而不是父类实例,所以父类实例上的属性方法无法通过super调用。(父类构造函数里this调用的属性方法就是实例属性方法)
class A {
constructor() {
this.p = 2;
}
}
class B extends A {
get m() {
return super.p;
}
}
let b = new B();
b.m // undefined
定义在父类实例上的属性应该是这样子
class A {}
A.prototype.x = 2;
class B extends A {
constructor() {
super();
console.log(super.x) // 2
}
}
let b = new B();
在普通方法中使用super 对象时, 方法内部的this指向当前的子类实例
class A {
constructor() {
this.x = 1;
}
print() {
console.log(this.x);
}
}
class B extends A {
constructor() {
super();
this.x = 2;
}
m() {
super.print();
}
}
let b = new B();
b.m() // 2
对象总是继承自另一个对象,所以可以在任意一个对象里使用super
var obj = {
toString() {
return "MyObject: " + super.toString();
}
};
obj.toString(); // MyObject: [object Object]
- 子类的构造方法如果没有写也会被自动添加。
- 子类的实例也是父类的实例
let cp = new ColorPoint(25, 8, 'green');
cp instanceof ColorPoint // true
cp instanceof Point // true
- 父类的static 方法会被子类继承
去class基本语法里会看到静态方法(属性)和私有方法(属性)的使用方法
静态方法只能直接通过类调用,但不能被实例继承,变量名:static variable
私有方法只能在类内部使用 ,变量名:#variable - 判断一个类是否继承了另一个类
Object.getPrototypeOf()可以获取子类的父类
Object.getPrototypeOf(child) === parent
// true
- 类的prototype属性和proto属性
大多数浏览器的 ES5 实现之中,每一个对象都有proto属性,指向对应的构造函数的prototype属性。Class 作为构造函数的语法糖,同时有prototype属性和proto属性,因此同时存在两条继承链。
(1)子类的proto属性,表示构造函数的继承,总是指向父类。
(2)子类prototype属性的proto属性,表示方法的继承,总是指向父类的prototype属性。
我知道这张图可能不准确,但是这样记能让我一下子找到对应关系。
- 子类原型的原型是父类的原型,emm
var p1 = new Point(2, 3);
var p2 = new ColorPoint(2, 3, 'red');
p2.__proto__ === p1.__proto__ // false
p2.__proto__.__proto__ === p1.__proto__ // true
image.png
这里有个作用就是通过子类的实例可以修改父类的实例
子类实例.proto.proto.attr = whatever;,修改父类,进而音箱父类的实例。
- 原生构造函数的继承
原生构造函数,是指语言内置的构造函数,用来生成数据结构,ES的构造函数有9种:
Boolean(),String(),Number(),
Object(),Array(),Function(),
Date(),RegExp(),Error(),
后面的我就不想写了...