JavaScript 实现继承的方式:原型链、组合式、寄生组合式

原型链继承

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.prototypechild 实例两个对象都有了 Parent 中的 namestaff 属性。

寄生组合继承

关键:

对于第一次调用,让 Child.prototype 有了 Parent 的属性,这是要避免的。

方法:

  • 创建一个空的函数中转一下;
  • Child 的原型 Child.prototype = 空函数的实例;
  • 让空函数的原型 F.prototype = Parent.prototype

代码描述

let F = function() {};
F.prototype = Parent.prototype;
Child.prototype = new F();

由此,child 通过 __proto__ 指向Child.prototypef ,又通过 __proto__ 指向 F.prototypeParent.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。开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。

参考:https://github.com/mqyqingfeng/Blog/issues/16

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值