js中的继承
- 构造函数 call(第一次调用父类构造函数)
- 原型链 子类原型 = 父类实例(第二次调用父类构造函数) 子类构造函数要指回自己
- 组合(1+2) 缺点:调用两次父类构造函数,性能浪费
- 原型 Object.create() 对父类prototype的浅复制
- 寄生(4的增强) 做constructor的指回
- 寄生组合(1+5) 无性能问题的完美继承方式
- ES6 class extends关键字的继承 与寄生组合一样,有一些 细节上的不同
这里从Object.create这个函数开始说起 内部实现为:
//原型继承
function object(o){
function F(){}
F.prototype = o
return new F()
}
//对原型继承进行增强的寄生继承
function createAnother(o){
var clone = object(o)
clone.say = function{ //以某种方式增强这个对象
console.log('Hi')
}
return clone
}
//ES5寄生组合实现自己的extends
function myExtends(SuperType,SubType){
var prototype = Object.create(SuperType.prototype) //实现了父类原型的浅复制
prototype.constructor = SubType //修正构造函数指向
SubType.prototype = prototype
}
function Super1(name){
this.name = name
}
Super1.prototype.say = function(){
console.log('hi')
}
function Sub1(name,age){
Supertype.call(this,name)
this.age = age
}
//核心:因为是对父类原型的浅复制,不包含父类的构造函数,所以不会调用两次父类的构造函数造成浪费
myExtends(Super1,Sub1)
Sub1.prototype.say() //hi
//完美继承
setPrototypeOf(A,B)方法
相当于 A.__proto__ = B
Object.setPrototypeOf = function(obj,proto){
obj.__proto__ = ptoto
return obj
}
getPrototypeOf(A)方法
得到A的__proto__
ES5和ES6继承的异同
ES5:寄生组合继承 使用Object.create(),父类构造函数的复制,没有原型链指向 先创建子类实例this对象,再对其增强 ES6:extends关键字 子类构造函数的原型链指向父类的构造函数 先将父类实例对象的属性和方法加到this上面,再用子类构造函数修改this,所以必须先调用super方法
//ES6 extends 继承
function _extends(SuperClass,SubClass){
//这里可以写成 Object.setPrototypeOf(SubClass.prototype,SuperClass.prototype)
SubClass.prototype.__proto__ = SuperClass.prototype //Sub的实例继承Super的实例
SubClass.prototype.constructor = SubClass
SubClass.__proto__ = SuperClass //Sub继承Super的静态属性
}
function SuperClass(name){
this.name = name
}
function SubClass(name,age){
_extends(SuperClass,SubClass) //将Sub的原型指向Super
SuperClass.call(this,name) //相当于super关键字
//也可以写成 Object.getPrototypeOf(SubClass) //==SuperClass
this.age = age
return this
}