前言


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

不了解可以去先阅读我另一篇文章,里面对原型链有一个较为详细的说明: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. PHP中命名空间是怎样的存在?(三)

    这是与命名空间有关的最后一篇.最后还是两个比较简单的内容,是关于命名空间和全局相关的一些类.函数.常量的使用对比.当然,最后我们还会总结一下命名空间的名称解析规则做为这三篇系列文章的结束. 全局空间 ...

  2. Linux系列(36) - yum命令安装(3)

    yum常用命令 查询 yum list:查询所有可用软件包列表 yum search 关键字:搜索服务器上所有和关键字相关的包 安装 yum -y install 包名 选项: -install 安装 ...

  3. 搞不定 NodeJS 内存泄漏?先从了解垃圾回收开始

    通常来说,内存管理有两种方式,一种是手动管理,一种是自动管理. 手动管理需要开发者自己管理内存,什么时候申请内存空间,什么时候释放都需要小心处理,否则容易形成内存泄漏和指针乱飞的局面.C 语言开发是典 ...

  4. 一文让你快速入门pytest框架

    pytest是什么 官方文档描述: pytest is a framework that makes building simple and scalable tests easy. Tests ar ...

  5. 『GoLang』面向对象

    我们总结一下前面看到的:Go 没有类,而是松耦合的类型.方法对接口的实现. 面向对象语言最重要的三个方面分别是:封装,继承和多态,在 Go 中它们是怎样表现的呢? Go实现面向对象的两个关键是stru ...

  6. 单页应用后退不刷新方案(vue & react)

    引言 前进刷新,后退不刷新,是一个类似app页面的特点,要在单页web应用中做后退不刷新,却并非一件易事. 为什么麻烦 spa的渲染原理(以vue为例):url的更改触发onHashChange/pu ...

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

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

  8. PHP的SPL扩展库(一)数据结构

    SPL 库也叫做 PHP 标准库,主要就是用于解决典型问题的一组接口或类的集合.这些典型问题包括什么呢?比如我们今天要讲的数据结构,还有一些设计模式的实现,就像我们之前讲过的观察者模式相关的接口在 S ...

  9. 解决 Asp.Net5 在视频文件下载预览时无法快进的问题

    前情提要 https://www.cnblogs.com/puzhiwei/p/15265005.html 在解决.Net5 如何修改Content-Disposition实现在线预览的功能后,我又遇 ...

  10. 最详细STL(一)vector

    vector的本质还是数组,但是可以动态的增加和减少数组的容量(当数组空间内存不足时,都会执行: 分配新空间-复制元素-释放原空间),首先先讲讲vector和数组的具体区别 一.vector和数组的区 ...