当你想要放弃了,一定要想象那些睡得比你晚、气的比你早、跑的比你还快、天赋比你还高的牛人,他们早已在晨光中,跑向那个你永远只能眺望的远方。
一、简介
1、Class可以通过extends关键字继承。
2、ES5的继承,实质先创建子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6的继承机制完全不同,实质是先创造父类的实例对象this(必须先调用super方法),然后再用子类的构造函数修改this。
3、在子类的构造函数中,只有调用super之后,才可以使用this关键字。因为子类实例的构建,是基于对父类实例加工,只有super方法才能返回父类实例。
二、Object.getPrototypeOf()
Object.getPrototypeOf方法可以用来从子类上获取父类。
例:
Object.getPrototypeOf(ColorPoint) === Point
// true
三、super关键字
作为函数使用
1、super作为函数时调用时,代表父类的构造函数。
2、ES6要求,子类的构造函数必须执行一次super函数。
3、super()只能用在子类的构造函数之中。
作为对象使用
1、super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
2、由于super指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super调用的。如果定义在父类的原型上,super就可以获取到。
四、类的prototype属性和proto属性
1、在ES5的实现之中,每一个对象都有proto属性,指向对应的构造函数的prototype属性。 Class作为构造函数的语法糖,同时有prototype属性和proto属性,因此同时存在两条继承链。
(1)子类的proto属性,表示构造函数的继承,总是指向父类。
(2)子类prototype属性的proto属性,表示方法的继承,总是指向父类的prototype属性。
两条继承链:作为一个对象,子类的原型(proto属性)是父类;作为一个构造函数,子类的原型对象(prototype属性)是父类的原型对象的实例。
实例的proto属性
1、子类实例的proto属性的proto属性,指向父类实例的__proto属性。也就是说,子类的原型的原型,是父类的原型。
五、原生构造函数的继承
1、原生构造函数是指语言内置的构造函数,通常用来生成数据结构。
- Boolean()
- Number()
- String()
- Array()
- Date()
- Function()
- RegExp()
- Error()
- Object()
2、ES5是先新建子类的实例对象this,再将父类的属性添加到子类上,由于父类的内部属性无法获取,导致无法继承原生的构造函数。如,Array构造函数有一个内部属性[[DefineOwnProperty]],用来定义新属性,更新length属性,这个内部属性无法在子类获取,导致子类的length属性不正常。
var colors = new MyArray();
colors[0] = "red";
colors.length // 0
colors.length = 0;
colors[0] // "red"
3、ES6允许继承原生构造函数定义子类,因为ES6是先新建父类的实例对象this,然后再用子类的构造函数修饰this,使得父类的所有行为都可以继承。
class MyArray extends Array {
constructor(...args) {
super(...args);
}
}
var arr = new MyArray();
arr[0] = 12;
arr.length // 1
arr.length = 0;
arr[0] // undefined