前言


首先学习继承之前,要对原型链有一定程度的了解。

不了解可以去先阅读我另一篇文章,里面对原型链有一个较为详细的说明:js 原型链详解。

如果已经了解请继续。

之前写过一篇博文将继承方式全部列出来了,不过我发现一口气看完过于长了,也不利于吸收知识,所以我先将组合继承部分划分出来,后续会把寄生部分补上。

原型链继承


父类实例作为子类的原型

子类创造的两个实例的隐式原型__proto__指向父类的那个实例

而父类的实例的隐式原型__proto__又指向父类的原型father.prototype

根据原型链的特性,所有子类的实例能够继承父类原型上的属性。

阅览以下这张图可以配合代码理解清晰。

    //父类
function father() {
this.fatherAttr = ["fatherAttr"];
} //父类的原型上的属性
father.prototype.checkProto = "checkProto"; //子类
function child() {} // 将father实例作为child这个构造函数的原型
child.prototype = new father();
child.prototype.constructor = child; //两个子类实例
const test1 = new child();
const test2 = new child(); console.log("测试1:");
console.log("test1:", test1);
console.log("test2:", test2);
console.log("test1.fatherAttr:", test1.fatherAttr);
console.log("test2.fatherAttr:", test2.fatherAttr); console.log("测试2:");
test1.fatherAttr.push("newAttr");
console.log("test1.fatherAttr:", test1.fatherAttr);
console.log("test2.fatherAttr:", test2.fatherAttr); console.log("测试3:");
console.log("test1.checkProto:", test1.checkProto);

特点:

  1. 两个实例对象都没有fatherAttr属性,但是因为父类的实例会拥有fatherAttr属性,且现在父类的实例作为child的原型,根据原型链,他们可以共享到自己的构造函数child的原型上的属性。(测试1)
  2. 因为只有一个父类的实例作为他们的原型,所以所有实例共享了一个原型上的属性fatherAttr,当原型上的属性作为引用类型时,此处是数组,test1添加一个新内容会导致test2上的fatherAttr也改变了。(测试2)(缺点)
  3. child构造函数不能传递入参。(缺点)
  4. 实例可以访问到父类的原型上的属性,因此可以把可复用方法定义在父类原型上。(测试3)

构造函数继承


将父类上的this绑定到子类,也就是当子类创造实例时会在子类内部调用父类的构造函数,父类上的属性会拷贝到子类实例上,所以实例会继承这些属性。

    //父类
function father(params) {
this.fatherAttr = ["fatherAttr"];
this.params = params;
} //父类的原型上的属性
father.prototype.checkProto = "checkProto"; //子类
function child(params) {
father.call(this, params);
} //两个子类实例
const test1 = new child("params1");
const test2 = new child("params2"); console.log("测试1:");
console.log("test1:", test1);
console.log("test2:", test2);
console.log("test1.fatherAttr:", test1.fatherAttr);
console.log("test2.fatherAttr:", test2.fatherAttr); console.log("测试2:");
test1.fatherAttr.push("newAttr");
console.log("test1.fatherAttr:", test1.fatherAttr);
console.log("test2.fatherAttr:", test2.fatherAttr); console.log("测试3:");
console.log("test1.checkProto:", test1.checkProto);

特点:

  1. 两个实例对象都拥有了拷贝来的fatherAttr属性,所以没有共享属性,创造一个实例就得拷贝一次父类的所有属性,且因为不能继承父类原型,所以方法不能复用,被迫拷贝方法。(测试1)(缺点)
  2. test1添加一个新内容只是改变了test1自己的属性,不会影响到test2。(测试2)
  3. child构造函数可以传递参数,定制自己的属性。(测试1)
  4. 实例不能继承父类的原型上的属性。(测试3)(缺点)

组合继承


结合原型链继承和构造函数继承,可以根据两种继承特点进行使用。

    //父类
function father(params) {
this.fatherAttr = ["fatherAttr"];
this.params = params;
} //父类的原型上的属性
father.prototype.checkProto = "checkProto"; //子类
function child(params) {
//第二次调用了父类构造函数
father.call(this, params);
} // 将father实例作为child构造函数的原型
child.prototype = new father();//第一次调用了父类构造函数
child.prototype.constructor = child; //两个实例
const test1 = new child("params1");//从这里跳转去子类构造函数第二次调用了父类构造函数
const test2 = new child("params2"); console.log("测试1:");
console.log("test1:", test1);
console.log("test2:", test2);
console.log("test1.fatherAttr:", test1.fatherAttr);
console.log("test2.fatherAttr:", test2.fatherAttr); console.log("测试2:");
test1.fatherAttr.push("newAttr");
console.log("test1.fatherAttr:", test1.fatherAttr);
console.log("test2.fatherAttr:", test2.fatherAttr); console.log("测试3:");
console.log("test1.checkProto:", test1.checkProto); console.log("测试4:");
delete test1.fatherAttr
console.log("test1:", test1);
console.log("test1.fatherAttr:", test1.fatherAttr);

特点:

  1. 两个实例对象都拥有了拷贝来的fatherAttr属性,创造一个实例就得拷贝一次父类的所有属性(构造函数继承特点,测试1),但是能访问父类原型,可以把复用方法定义在父类原型上。(原型链继承特点,测试1)
  2. test1添加一个新内容只是改变了test1自己的属性,不会影响到test2。(构造函数继承特点,测试2)
  3. child构造函数可以传递参数,定制自己的属性。(构造函数继承特点,测试1)
  4. 实例能继承父类的原型上的属性。(原型链继承特点,测试3)
  5. 调用了两次父类的构造函数,生成两份实例,创建子类原型链一次,用子类创建实例时,子类内部里面一次,第二次覆盖了第一次。(缺点)
  6. 因为调用两次父类构造函数,如果用delete删除实例上拷贝来的fatherAttr属性,实例仍然拥有隐式原型指向的父类实例上的fatherAttr属性。(原型链继承特点,测试4)(缺点)

js 组合继承详解的更多相关文章

  1. 《Node.js开发实战详解》学习笔记

    <Node.js开发实战详解>学习笔记 ——持续更新中 一.NodeJS设计模式 1 . 单例模式 顾名思义,单例就是保证一个类只有一个实例,实现的方法是,先判断实例是否存在,如果存在则直 ...

  2. Js apply 方法 详解

    Js apply方法详解 我在一开始看到JavaScript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...

  3. ES6,ES2105核心功能一览,js新特性详解

    ES6,ES2105核心功能一览,js新特性详解 过去几年 JavaScript 发生了很大的变化.ES6(ECMAScript 6.ES2105)是 JavaScript 语言的新标准,2015 年 ...

  4. Js apply()使用详解

    Js apply方法详解 我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...

  5. Js apply方法详解,及其apply()方法的妙用

    Js apply方法详解 我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...

  6. [原创]JavaScript继承详解

    原文链接:http://www.cnblogs.com/sanshi/archive/2009/07/08/1519036.html 面向对象与基于对象 几乎每个开发人员都有面向对象语言(比如C++. ...

  7. Vue.js 数据绑定语法详解

    Vue.js 数据绑定语法详解 一.总结 一句话总结:Vue.js 的模板是基于 DOM 实现的.这意味着所有的 Vue.js 模板都是可解析的有效的 HTML,且通过一些特殊的特性做了增强.Vue ...

  8. “全栈2019”Java第九十九章:局部内部类与继承详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  9. JS hashMap实例详解

    链接:http://www.jb51.net/article/85111.htm JS hashMap实例详解 作者:囧侠 字体:[增加 减小] 类型:转载 时间:2016-05-26我要评论 这篇文 ...

随机推荐

  1. TP5路由的位置导致错误

    // 测试 '[js]' => [ ':id' => ['test/test/js', ['method' => 'get'], ['id' => '\d+']], ':id/ ...

  2. 如何实现Orchard Core CMS的全文索引

    Orchard Core提供了Lucene功能,允许您在网站上进行全文搜索.大多数情况下,在运行博客或简单的代理网站时,您可能需要在页面内容中进行搜索.在Orchard Core中,您可以使用Liqu ...

  3. python在iis获取header

    #print os.environ['QUERY_STRING']#print os.environ['HTTP_HOST'] #print '---------------------------- ...

  4. 整理常用的 vim 命令

    vim 是一款功能强大的文本编辑器,它是Linux下常用的编辑器之一,对于熟练掌握了 vim 的人来说,用它编辑文件,方便又快捷,能极大的提高工作效率 vim 功能强大,对应的命令也非常的多,对于初学 ...

  5. SQL Server 命令备忘录(持续更新...)

    1.删除表内容并重置ID truncate table 表名 2.开启SqlDependency监控数据库 在数据中执行以下查询: SELECT is_broker_enabled FROM sys. ...

  6. SQL Server附加数据库错误5120处理方法

    SQL Server附加数据库5120错误 当我们从另外一台服务器复制过来的数据库,可能会有如下错误: 解决方法 1.给数据库所在文件夹增加用户Everyone并赋予完全控制权限 2.以管理员身份运行 ...

  7. Snipaste屏幕截图的使用

    什么是Snipaste Snipaste是一款屏幕截图软件 类似于微信的截图 Snipaste使用步骤 百度搜索Snipaste 如图 点击 根据自己电脑系统选择安装 下载完成后 解压到当前文件夹 点 ...

  8. LightningChart XY功能中的常见问题

    LightningChart XY功能中的常见问题 XY 是LightningChart 的重要功能之一,也是被用户使用最广泛的.用户经常对这个功能有着这样那样的疑问,现在将一些常用问题汇总了一下,希 ...

  9. EPUB文件格式简单解析

    最近热衷于看轻小说,奈何某些网站样式排版属实糟糕,移动端体验极度不友好,实在无法忍受,于是希望能将网站内容爬取下来制作成EPUB格式的电子书. 抛开爬取网站内容不谈,通过解析EPUB文件后,大致掌握了 ...

  10. C#并行编程:Parallel的使用

    前言:在C#的System.Threading.Tasks 命名空间中有一个静态的并行类:Parallel,封装了Task的使用,对于执行大量任务提供了非常简便的操作.下面对他的使用进行介绍. 本篇内 ...