Class的方法都加在原型链上
JS的原型链继承的本质是根据__proto__一层一层往上找
继承的时候只需要把子类的原型对象prototype里的__proto__属性指向父类的prototype即可
这就好理解Extends在干嘛了
class A {
// constructor也是定义在A的原型链上
constructor(x,y){
this.x = x;
this.y = y;
}
// 直接加在了function A 的原型链式
one(){
return 1;
}
}
class B extends A{
constructor(){
//相当于A.prototype.constructor.call(this)
super(1,2)
}
}
var x = new B()
console.log(x)
继承的时候extends干了什么
extends在实现继承方面,本质上也是原型链继承,该方法实现了两步原型链继承
大多数浏览器的 ES5 实现之中,每一个对象都有__proto__属性,指向对应的构造函数的prototype属性。
Class 作为构造函数的语法糖,同时有prototype属性和__proto__属性,因此同时存在两条继承链。
- (1)子类的__proto__属性,表示构造函数的继承,总是指向父类。(把子类构造函数(
Child
)的原型(__proto__
)指向了父类构造函数(Parent
),) - (2)子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。
第一步是将类的原型对象(prototype)里的__proto__指向父类的原型对象:
B.prototype = Object.create(A.prototype, {constructor:{value: B}})
即将B.prototype.__proto__ =A.prototype
第二步是将类的__proto__指向父类:
(子类是父类构建出的函数对象,需要指定对象的__proto__)
Object.setPrototypeOf(B, A);
即将B.__proto__ =A (B由A构造而来)
最后需要继承构造函数里的属性和方法
内部写的有点绕,但最后还是通过apply(this, arguments)来继承的
(function(_A) {
//继承原型对象上的属性和方法
_inherits(B, _A);
function B() {
_classCallCheck(this, B);
//继承构造函数中的实例属性和方法
return _possibleConstructorReturn(
this,
_getPrototypeOf(B).apply(this, arguments)
);
}
return B;
})(A);
babeljs对extends语法糖的部分编译结果
function _inherits(subClass, superClass) {
//对superClass进行类型判断
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
//子类的prototype继承父类的prototype
//也就是说执行后 subClass.prototype.__proto__ === superClass.prototype; 这条语句为true
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true
}
});
//子类是父类构建出的函数对象,需要指定对象的__proto__
if (superClass) _setPrototypeOf(subClass, superClass);
}
联系寄生组合继承(call+寄生式封装)
寄生组合式继承原理:
- 使用借用构造函数(
call
)来继承父类this声明的属性/方法 - 通过寄生式封装函数设置父类prototype为子类prototype的原型来继承父类的prototype声明的属性/方法。
可以发现ES6类的继承其实就是基于寄生组合继承来实现的
function inheritPrototype(subType, superType){
//原型式继承:浅拷贝superType.prototype对象作为superType.prototype为新对象的原型
// 内部会自带_proto_指向:prototype.\_\_proto\_\_ = superType.prototype;
var prototype = Object.create(superType.prototype);
// subType.prototype.\_\_proto\_\_ = superType.prototype;
subType.prototype = prototype; // 将子类的原型替换为这个原型
prototype.constructor = subType; // 修正原型的构造函数
}
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
SuperType.call(this, name);
this.age = age;
}
// 核心:因为是对父类原型的复制,所以不包含父类的构造函数,也就不会调用两次父类的构造函数造成浪费
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function(){
alert(this.age);
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。