目录

  • 前言
  • 一、原型链继承
    • 原型链继承的概念
    • 原型链继承的不足
  • 二、借用构造函数继承
    • 借用构造函数继承的概念
    • 利用构造函数继承的不足
  • 三、组合继承(原型链继承+构造函数继承)
    • 组合继承的概念
    • 组合继承的缺陷
  • 四、寄生组合性继承
    • 寄生组合性继承的概念
    • 寄生组合性继承的优点
  • 多重继承
    • 多重继承的概念
  • 总结

前言

在JS中既然没有类,那继承也是没有的,但面对家财万贯的家产时,我们又岂能无动于衷呢?于是我们想到了用模拟的方式,实现继承。

一、原型链继承

原型链继承的概念

在前一篇文章(javaScript(ES5)面向对象——原型模式实现原理),我们已经分析过了,在JS中每一个对象都存在原型对象,且可以通过原型对象共享属性和方法。原型链继承就是通过改变子类的原型对象为父类的原型对象,从而实现继承。
见图所示:

实现代码:

function Farther(){this.name = ['hello'];this.money = 999999;
}
Farther.prototype.say = function(){console.log(this.name);
}function Son(){}// 原型链继承
Son.prototype = new Farther();
Son.prototype.constructor = Son;
var xdl = new Son();
console.log(xdl.money);   // 999999
xdl.say();     // ["hello"]

原型链继承的不足

原型链继承一共有以下两个问题:

  1. 原型链继承中,子类的实例对象会共享父类的实例对象属性,当父类的实例对象属性是引用数据类型时,一旦子类中的实例对象对其修改,则子类所有的实例对象所继承的相应属性值都会发现改变
var xdl = new Son('xdl');
var xdl2 = new Son('xdl2');
xdl.name.push('world!');
console.log(xdl.name);   // ["hello", "world!"]
console.log(xdl2.name);  // ["hello", "world!"]
  1. 当创建子类的实例对象时,无法传参给父类,也就无法使用父类的构造函数

二、借用构造函数继承

借用构造函数继承的概念

为了解决使用原型链继承无法在创建子类实例对象时,无法传参给父类的缺陷,因此我们使用call(apply、bind)的方式来调用父类的构造函数,从而实现子类向父类传参的效果。

实现代码:

function Father(name){this.name = name;this.sleep = function(){console.log('正在睡觉');}
}
Father.prototype.money = 999999;
Father.prototype.say = function(){console.log(this.name);
}function Son(name){Father.call(this, name);
}var xdl = new Son('xdl');
console.log(xdl.name);  // xdl
console.log(xdl.money);  // undefined
console.log(xdl);

打印结果:

利用构造函数继承的不足

我们在打印结果中可以看出,子类只继承了父类的实例对象属性和方法,但父类的原型对象并没有被继承下来。也就是说,父亲的家产没有被继承下来啊,那怎么行!

三、组合继承(原型链继承+构造函数继承)

组合继承的概念

原型链继承和构造函数继承,都各有各的优点与缺点,都说鱼和熊掌不可兼得,但为了继承到完整的家产,我们必须要拼命想办法继承。

实现代码:

function Father(name){this.name = name;console.log('我被调用了');
}
Father.prototype.money = 999999;function Son(name){Father.call(this, name);
}Son.prototype = new Father();  // 父类的创建的对象当作子类的原型对象
Son.prototype.constructor = Son;
var xdl = new Son('xdl');
console.log(xdl);
console.log(xdl.money);

运行结果:

组合继承的缺陷

分析结果我们可以得出,父类的构造函数会被调用两次:一次是实例化子类属性和方法,第二次是继承父类的共享属性和方法

四、寄生组合性继承

寄生组合性继承的概念

在组合继承中无非就是调用父类构造函数的次数过多,那我们就想办法减少调用的次数。那我们应该从哪里入手?
我们来分析一下:一共有两个地方调用父类的构造函数,第一个地方:Father.call(this, name);,这个地方是通过call的方式,调用父类构造函数,从而继承父类实例对象的属性和方法;第二个地方Son.prototype = new Father();,这个地方是将父类的实例对象当作子类的原型对象,继承父类的共享属性和方法。第一个地方无法优化,但第二个地方,不就是要得到父类的原型对象吗?那我们直接把父类的原型对象取出来,再用Object.create()以父类的原型对象为基础创建一个对象,最后作为子类的原型对象。
实现代码:

function Father(name){this.name = name;
}
Father.prototype.money = 999999;function Son(name){Father.call(this, name);
}Son.prototype = Object.create(Father.prototype);  // 优化的地方
Son.prototype.constructor = Son;
var xdl = new Son('xdl');
console.log(xdl);
console.log(xdl.money);

运行结果:

寄生组合性继承的优点

寄生组合性继承中,创建子类的实例对象时,可以向父类传参继承父类实例对象的属性和方法,同时还可以继承父类的原型对象,得到共享的属性和方法,并且不会像组合性继承那样调用两次父类构造函数,成功继承父亲全部的家产!

多重继承

多重继承的概念

在前面,我们成功继承了父亲的全部家产,但是母亲的家产呢?母亲给予我们更多的是暖暖的母爱,所以我们必须要得到这无价的爱。这就涉及到了多重继承的问题,在JS中通过混入技术(把另外一个对象拷贝到当前原型链上),把父类的原型对象拷贝到当前的原型链上,从而实现多重继承。

实现代码:

function Animal(name){this.name = name;
}function Father(){this.name = '父亲';
}
Father.prototype.money = 999999;function Mother(){this.name = '母亲'
}
Mother.prototype.love = function(){console.log('母亲的关爱');
}function Son(name){Animal.call(this, name);
}Son.prototype = Object.create(Father.prototype);
Object.assign(Son.prototype, Mother.prototype);
Son.prototype.constructor = Son;
var xdl = new Son('xdl');
console.log(xdl);
console.log(xdl.money);
xdl.love();

运行结果:

总结

谁说鱼和熊掌不能兼得?成功通过足智多谋,继承到了父母的家产,父母再也不用担心家产没有人继承了!

javaScript(ES5)中想方设法继承家产的方式详解相关推荐

  1. js继承的六种方式详解--认真看完你就会了

    今天 主要来研究一下继承这个东西 继承 共分为六种继承方式: 原型链继承 盗用构造函数继承 组合继承 实例继承(原型式继承) 寄生式继承 寄生式组合继承 原型链继承 原型链继承是ES主要继承方法,其中 ...

  2. asp.net Session在web.config中的三种配置方式——详解

    这段代码就是设置session在web.config中的存储方式. < sessionState mode="Off|InProc|StateServer|SQLServer" ...

  3. @AspectJ中的几种通知方式详解

    本文来详细说下@AspectJ中的几种通知方式 文章目录 概述 通知方式说明 一个例子 本文小结 概述 当Spring 2.0发布以后,Spring AOP增加了新的使用方式,Spring AOP集成 ...

  4. Unity3D中UGUI的RectTransform对齐方式详解

    https://www.jianshu.com/p/831e2dd7c546 https://www.jianshu.com/p/4592bf809c8b 在Unity自带的UGUI中,RectTra ...

  5. java clone方法_干货满满:Java中创建对象的五种方式详解

    通常来说,对象具有状态和行为,变量用来表明对象的状态,方法表明对象所具有的行为. 作为Java开发者,我们通常都是使用依赖管理系统,比如Spring去创建Java对象,但使用管理系统创建对象并不是唯一 ...

  6. java中三种基本循环方式详解

    #博学谷IT学习技术支持# Java循环for,while和do-while 简述:如果对于同一种操作需要执行多次的话,就要使用到循环结构.它可以大大简化代码的书写量,让我们的开发更便捷. 例如:打印 ...

  7. php中 继承中的概念,JavaScript_JavaScript中的继承方式详解,js继承的概念 js里常用的如下 - phpStudy...

    JavaScript中的继承方式详解 js继承的概念 js里常用的如下两种继承方式: 原型链继承(对象间的继承) 类式继承(构造函数间的继承) 由于js不像java那样是真正面向对象的语言,js是基于 ...

  8. 7种方法实现ES5中的继承

    7种方法实现ES5中的继承 1.借用构造函数继承父类属性 步骤 实现示例 优缺点 2.利用原型对象继承父类方法 步骤 实现示例 优缺点 3.组合继承 步骤 实现示例 优缺点 4.寄生式继承 步骤 实现 ...

  9. C++的三种继承方式详解

    文章目录 @[toc] C++的三种继承方式详解以及区别 前言 一.public继承 二.protected继承 三.private继承 四.三者区别 五.总结 后话 C++的三种继承方式详解以及区别 ...

最新文章

  1. x86汇编语言从实模式百度云_Intel x86 CPU 32位保护模式杂谈之任务切换 上
  2. php dropdownlist,遇到dropdownlist
  3. linux终端刷新网络命令,在Ubuntu Linux操作系统中重新启动网络的方法
  4. java解析json_JAVA解析JSON数据
  5. 【类】变量复用,函数复用
  6. ubuntu完全清除mysql残留文件和配置
  7. 2019重庆对口高职计算机类分数排名,重庆2019高职分类考试分数线公布
  8. spark dataframe常用操作集锦
  9. 基于AI的恶意软件分析技术(3)
  10. 实现fashion_minst服装图像分类
  11. 如何在数据库mysql中储存图片
  12. Java版数据结构之单向链表
  13. Flask数据库_filter过滤器的使用
  14. 盛世昊通全新升级,引领智慧新经济
  15. 解决火绒提示helper_haozip.exe文件是病毒威胁
  16. 新手零基础:飞桨代码中关于图片路径读取和资源解压报错
  17. 服务自省,Dubbo面向了应用级
  18. Apache的虚拟主机配置和伪静态操作
  19. Python BDD 框架之lettuce
  20. XML Schema教程

热门文章

  1. SD Card Driver
  2. 入侵你Linux服务器的一万种玩法...
  3. 编写函数求解一元二次方程
  4. 算法与程序设计相关知识
  5. oracle锁矩阵,你有多了解Oracle Enqueue lock队列锁机制?
  6. 北大ACM暑期培训感想
  7. [实用技巧] (转帖)关于MyDocument.exe -- 打印店病毒
  8. Vue—单页面应用与多页面应用的区别
  9. 优达学城《无人驾驶入门》学习笔记——卡尔曼滤波器实现详解
  10. 仿qq音乐官网部分静态页面