1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > JavaScript面向对象——深入理解寄生组合继承

JavaScript面向对象——深入理解寄生组合继承

时间:2021-12-31 10:08:32

相关推荐

JavaScript面向对象——深入理解寄生组合继承

JavaScript面向对象——深入理解寄生组合继承

之前谈到过组合继承,会有初始化两次实例方法/属性的缺点,接下来我们谈谈为了避免这种缺点的寄生组合继承

寄生组合继承:

思路:组合继承中,构造函数继承时已经继承了父类中除了通过prototype定义的公有属性和方法,也就是说我们需要在原型继承时继承父类的原型而不执行父类的构造函数,这样就避免了组合继承中的缺点。

思路有了,如何实现?

让我们从名字入手,寄生组合继承,组合继承我们谈过了,寄生是什么东西?《JavaScript设计模式》这本书中说得比较模糊,因此本人阅读了另一本更专于介绍JavaScript面向对象的书《JavaScript面向对象编程指南第2版》,感觉这本书挺好的,推荐一下:

插播:寄生式继承

思路:在创建对象的函数中直接吸收其他对象的功能,然后对其进行扩展并返回。

步骤:

1:设计inheritObject()函数,名称自定,只是举例

设计理念:函数可以用来接收新对象,并返回一个以该对象为原型的新对象

function inheritObject(o) {function F() {}F.prototype = oreturn new F()}

2:使用对象标识法定义一个普通对象

var twoD = {name: '2D shape',dimensions: 2}

3:使用inheritObject()函数对twoD进行操作

function triangle(s, h) {var that = inheritObject(twoD)that.name = 'Triangle'that.side = sthat.height = hthat.getArea = function () {return that.side * that.height / 2}return that}

说明:triangle()中使用inheritObject()将twoD克隆进that对象,并对that对象进行了扩展然后返回。(寄生式继承的思路:在创建对象的函数中直接吸收其他对象的功能,然后对其进行扩展并返回,在此函数中实现。)注意:这个that只是个名称,可以随便换另一个,没有跟保留字this那样的含义。

这种继承方式下创建对象,使不使用new都可以,因为返回的就是一个对象。

// testvar t = triangle(5, 10)console.log(t.dimensions)var t2 = new triangle(5, 5)console.log(t2.getArea())

结果:

插播了一下寄生式继承的实现,现在我们重新谈谈寄生组合继承....

寄生组合继承思路回忆:组合继承中,构造函数继承时已经继承了父类中除了通过prototype定义的公有属性和方法,也就是说我们需要在原型继承时继承父类的原型而不执行父类的构造函数,这样就避免了组合继承中的缺点。

实现方案:寄生式继承+组合继承,代码中使用到上边提到的inheritObject()函数。

function inheritPrototype(subClass, superClass) {// 复制一份父类的原型副本保存在变量中var p = inheritObject(superClass.prototype)// 修正因为重写子类原型导致子类的constructor属性被修改p.constructor = subClass// 设置子类的原型subClass.prototype = p}

解释:因为我们只需要父类原型对象的一个副本,这个副本通过原型继承便可以得到,但是直接赋值给子类是会有问题的,因为对父类对象复制得到的对象p中的constructor指向的不是SubClass子类对象,因此寄生式继承中要修复复制对象p的constructor属性指向不正确的问题,最后得到的复制对象p赋值给子类的原型,这样子类的原型就继承了父类的原型并且没有执行父类的构造函数。

测试例子:

// 定义父类function SuperClass(name) {this.name = namethis.colors = ['red', 'orange', 'yellow']}// 定义父类原型方法SuperClass.prototype.getName = function () {console.log(this.name)}// 定义子类function SubClass(name, time) {// 构造函数式继承SuperClass.call(this, name)// 子类新增属性this.time = time}// 寄生式继承父类原型inheritPrototype(SubClass, SuperClass)// 子类新增原型方法, 不可以写在寄生式继承父类原型函数前SubClass.prototype.getTime = function () {console.log(this.time)}// 创建测试实例var instance1 = new SubClass('JavaScript', '-03-18')var instance2 = new SubClass('NodeJs', '-03-19')instance1.colors.push('green')console.log(instance1.colors)console.log(instance2.colors)instance1.getName()instance1.getTime()instance2.getName()instance2.getTime()

解释:多数跟组合继承的一样,除了这点:子类原型被赋予了父类原型的一个引用,这是个对象,也就是引用类型,所以给子类添加原型方法时只可以通过prototype.语法,不可以使用subClass.prototype={xxx:function(){}}这种对象赋值式的写法,否则父类的原型会被覆盖。

运行结果终于来了.....

最后来一张寄生组合继承的原理图,理解了的伙伴请忽略,周日愉快,晚安~(.03.18)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。