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', '2018-03-18')var instance2 = new SubClass('NodeJs', '2018-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(){}}这种对象赋值式的写法,否则父类的原型会被覆盖。

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

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

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

  1. JavaScript面向对象——深入理解默认的继承方式原型链

    描述: 正如我们所了解,JavaScript中的每个函数中都有一个指向某一对象的prototype属性.该函数被new操作符调用时会创建并返回一个对象,并且该对象中会有一个指向其原型对象的秘密链接,通 ...

  2. JavaScript简餐——寄生组合继承

    文章目录 前言 一.什么是寄生组合继承? 二.寄生组合继承的基本模式 三.总结 前言 写本<JavaScript简餐>系列文章的目的是记录在阅读学习<JavaScript高级程序设计 ...

  3. JavaScript简餐——关于寄生式继承

    文章目录 前言 一.什么是寄生式继承? 二.使用实例 三.总结 前言 写本<JavaScript简餐>系列文章的目的是记录在阅读学习<JavaScript高级程序设计(第4版)> ...

  4. (二)Javascript面向对象编程:构造函数的继承

    Javascript面向对象编程:构造函数的继承 这个系列的第一部分,主要介绍了如何"封装"数据和方法,以及如何从原型对象生成实例. 今天要介绍的是,对象之间的"继承&q ...

  5. JavaScript面向对象的理解

    前言 1. 本文默认阅读者已有面向对象的开发思想,最好是使用过c++.java,本人Java不太熟悉,所以例子都是用C++来写的. 2. 本人不是专业网站开发人员,接触javascript一年多,自己 ...

  6. JavaScript面向对象——深入理解原型继承

    JavaScript继承--深入理解原型继承 原型继承 // 父类function School (name, address) {this.name = namethis.address = add ...

  7. JavaScript面向对象编程理解

    对编程有了解的同学都知道,面向对象是一个非常难以理解的概念,下面给大家分享一下对象object的理解,本篇文章主要分享面对对象的封装.当然现实生活中面向对象也挺难的,哈哈哈~ 一,关于实例对象的原始模 ...

  8. 前端技巧|JavaScript面向对象编程理解

    对编程有了解的同学都知道,面向对象是一个非常难以理解的概念,下面给大家分享一下对象object的理解,本篇文章主要分享面对对象的封装.当然现实生活中面向对象也挺难的,哈哈哈~       一,关于实例 ...

  9. Javascript面向对象编程:构造函数的继承

    今天要介绍的是,对象之间的"继承"的五种方法. 比如,现在有一个"动物"对象的构造函数. function Animal(){ this.species = & ...

最新文章

  1. matlab julian day,通用的日期格式与儒略日(julian day)格式的互相转换
  2. HDU 1026 Ignatius and the Princess I(BFS)
  3. c#操作数据库(二)dataAdapter篇
  4. 《UML面向对象设计基础》—第1章1.5节消息
  5. c语言函数的程序设计,C语言程序设计第3版,第6章函数程序设计.ppt
  6. 深入理解ElasticSearch(八):索引管理
  7. 数据库运维:检查不同数据库中表的差异方案
  8. 2345天气王怎么查看历史天气 2345天气王如何查看历史天气
  9. Eclipse 编码区-保护色-快捷大全
  10. Spring:aspectj-autoproxy 简介
  11. 计算机d盘不显示容量,电脑D盘可用空间小,可是看不到文件
  12. ElasticSearch入门系列(一)是什么以及安装和运行
  13. 移动计算的未来:是什么在推动变革? | 幂集创新
  14. Python学习[4]:urllib库-爬虫的第三步之代理IP
  15. 使用keytool转换签名证书格式,keyStore、jks签名证书相互转换
  16. 网络调试助手连接远程服务器
  17. python脚本自动发送邮件和叮叮机器人发送群消息
  18. SVAC1.0帧间预测技术分析
  19. 程序员的终极浪漫,用python画一棵你的专属圣诞树
  20. xcode7.1生成打包上传时需要注意的东西

热门文章

  1. 受限玻尔兹曼机(Restricted Boltzmann Machine)分析
  2. PHP代码调试神器Whoops
  3. VMM系列之VMM角色介绍以及创建运行方式账户
  4. JavaScript的面向对象特性
  5. 洛谷P1082 同余方程 数论
  6. UITableView加载几种不同的cell
  7. (实用)Ubuntu 开启NFS服务
  8. 9月第1周国内搜索类网站频道:百度覆盖数创新高
  9. ASP.NET中进行消息处理(MSMQ)
  10. Android在使用WebView时,通过Javascript调用JAVA函数