class的继承
extends
class Point {
}
class ColorPoint extends Point {
}
通过extends关键字,实现子类对父类的继承
但是在继承父类时,必须使用super关键字,调用父类的构造方法,首先生成一个父类的this对象,得到与父类相同的属性或方法,再对其进行加工,添加自己的属性和方法,才能得到自己的this对象。
class Point { constructor(x, y) { this.x = x; this.y = y; } } class ColorPoint extends Point { constructor(x, y, color){ super(x, y); this.color = color; } }
在子类中,必须首先使用super,才能使用this关键字,因为this需要基于super先生成再改造。如果以上代码将this.color = color放到super之前,会报错。
通过子类生成的实例,同时是父类和子类的实例
子类会继承父类的静态方法。
Object.getPropertyOf()
可以用来获取子类的父类,从而判断一个类是否继承了另一个类
Object.getPropertyOf(ColorPoint) === Point // true
类的prototype和__proto__
Class作为构造函数的语法糖,同时具有prototype和__proto__属性,存在两条继承链
class father{ } class son extends father{ } son.__proto__ === father //true son.prototype.__proto__ === father.prototype // true
这样的结果是因为,类的继承是如下方式实现的
class A{}
class B extends A{}
Object.setPropertyOf(B.prototype, A.prototype);
Object.setPropertyOf(B, A);
而setPropertyOf方法的实现如下:
Object.setPropertyOf = funtion(obj, proto){ obj.__proto__ = proto; return obj; }
因此,以上类的继承
B.prototype.__proto__ = A.prototype
B.__proto__ = A
只要的内部有prototype属性的函数都能被继承,而所有的函数都有prototype属性,所以任何函数都能被继承
当A类作为基类时,其就是一个普通的函数,因此直接继承Function.prototype。而这个基类创建的实例是一个空对象,A.prototype__proto__又指向了Object.prototype
class A{} A.__proto__ === Function.prototype // true A.prototype.__proto__ === Object.prototype //true
实例的__proto__属性
class P1{
constructor(name){
this.name = name
}
sayHi(){
console.log('hi~p1')
}
}
class P2 extends P1{
}
var p1 = new P1('ashen');
var p2 = new P2();
console.log(p2.__proto__.__proto__ === p1.__proto__) // true
子类实例的原型的原型,指向父类实例的原型
正因如此,通过在子类实例的原型的原型可以更改父类的方法。但不能更改父类的实例属性
p2.__proto__.__proto__.sayHi = function () { console.log('hi~p2') } p2.__proto__.__proto__.name = 'xing' p1.sayHi() // hi~p2
console.log(p1.name) // ashen
构建原型构造函数的子类
在ES5中,继承都是先创建子类的this,再将父类的属性添加到子类上。然而父类的内部属性无法获取,也就无法继承原生的构造函数
而在ES6中,是先创建父类的this,然后用子类的属性和方法修饰this。所以继承了父类所有的内部属性。因此在ES6中可以构造原型构造函数的子类,如下实现数组构造函数的继承
class myArray extends Array{ constructor(...args){ super(...args); } } var arr = new myArray(); arr[0] = 12; console.log(arr.length); arr.length = 0; console.log(arr[0]);
既然可以继承数据类型的构造函数,那么就可以在此基础上定义自己的数据结构
但是在继承Object构造函数时有一个注意点
class myObj extends Object{ constructor(){ super(...arguments) } } var o = new myObj({attr: true}); console.log(o.attr) // undefined
无法通过super向父类构造函数传参。这是因为ES6中改变了Object构造函数的设置,当不是通过new Object()创建对象时,ES6就规定Object()构造函数忽略参数