原型链继承
let Parent = function() {
this.name = [‘parent']
}
Parent.prototype.sayName = function() {
console.log(this.name)
}
let Child = function(){}
Child.prototype = new Parent() //原型式继承
let child1 = new Child()
child1.sayName() //[‘parent’]
child1.name.push(‘child’)
let child2 = new Child()
child2.sayName() //[‘parent’, ‘child']
问题:
- 所以实例共享引用类型的属性,一改都改;
- 且创建 child 实例无法向 Parent 传参
组合式继承
这是 JavaScript 中最常用的继承模式。
let Parent = function(name){
this.name = name
this.staff = [‘a']
}
Parent.prototype.sayName = function(){
console.log(this.name)
}
Parent.prototype.showStaff = function(){
console.log(this.staff)
}
let Child = function(name){
Parent.call(this, name) //借用 Parent 构造函数,实现向其传参 (第二次)
}
Child.prototype = new Parent() // 继承 Parent 原型上的方法 (第一次)
let child1 = new Child(‘child1’)
let child2 = new Child(‘child2’)
child1.sayName() //child1
child2.sayName() //child2
child1.staff.push(‘child1’)
child1.showStaff() //[‘a’, ‘child1’]
child2.showStaff() //[‘a’]
问题:
两次调用 Parent
构造函数,分别让 Child.prototype
、child
实例两个对象都有了 Parent
中的 name
、staff
属性。
寄生组合继承
关键:
对于第一次调用,让 Child.prototype
有了 Parent
的属性,这是要避免的。
方法:
- 创建一个空的函数中转一下;
- 让
Child
的原型Child.prototype
= 空函数的实例; - 让空函数的原型
F.prototype = Parent.prototype
。
代码描述
let F = function() {};
F.prototype = Parent.prototype;
Child.prototype = new F();
由此,child
通过 __proto__
指向Child.prototype
即 f
,又通过 __proto__
指向 F.prototype
即 Parent.prototype
事实上,上面的思路就是 Object.create()
的实现
用代码描述:
function create (obj) {
let F = function(){}
F.prototype = obj
return new F()
}
由于 Child.prototype = new F()
,需要重新做 constructor
等指向,最后得
function inheritPrototype (subType, superType) {
let prototype = Object.create(superType.prototype)
subType.prototype = prototype
prototype.constructor = subType
寄生组合继承代码
let Parent = function(name){
this.name = name
this.staff = [1]
}
Parent.prototype.sayName = function(){
console.log(this.name)
}
Parent.prototype.showStaff = function(){
console.log(this.staff)
}
let Child = function(name){
Parent.call(this, name)
}
//Child.prototype = new Parent()
function inheritPrototype (subType, superType) {
let prototype = Object.create(superType.prototype)
subType.prototype = prototype
prototype.constructor = subType
}
inheritPrototype(Child, Parent)
let child1 = new Child(‘child1’)
child1.sayName()
let child2 = new Child(‘child2’)
child2.sayName()
child1.staff.push(2)
child1.showStaff()
child2.showStaff()
好处
《JavaScript高级程序设计》表示:
这种方式的高效率体现它只调用了一次 Parent 构造函数,并且因此避免了在 Parent.prototype
上面创建不必要的、多余的属性。与此同时,原型链还能保持不变;因此,还能够正常使用 instanceof 和
isPrototypeOf。开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。