前言


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

不了解可以去先阅读我另一篇文章,里面对原型链有一个较为详细的说明: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. TP6生成url

    和TP5生成url方式有区别, 在控制器里 需要加上 ->build(), 如 url('index/arc/list')->build(); 如果是多域名还需要指定域名,如不想加域名可以 ...

  2. js 获取转换网址中文参数

    var search = decodeURI(location.search).substr(1); console.log(search); decodeURI 方法返回一个已编码的统一资源标识符 ...

  3. CI框架页面打开空白,无报错为解决方法新环境

    1.打开错误显示,可以在控制controllers的首页入口加入以下代码,查看错误 error_reporting(-1); ini_set('display_errors', 1); //插入显示所 ...

  4. Docker系列(1) - Centos8.X安装Docker

    环境准备 需要会Linux的基础 Centos8.x 使用Xshell连接远程服务器 环境查看 #系统内核是4.18以上 [root@localhost ~]# uname -r 4.18.0-305 ...

  5. 初探DispatcherServlet#doDispatch

    初探DispatcherServlet#doDispatch 写在前面 SpringBoot其实就是SpringMVC的简化版本,对于request的处理流程大致是一样的, 都要经过Dispatche ...

  6. ubuntu系统执行生成密匙命令后,home目录下面没有生成.ssh目录

    ubuntu系统配置git ssh时,执行:ssh-keygen -trsa -C "youremail@example.com",home目录下面没有生成.ssh目录. .ssh ...

  7. Jenkins无法登陆解决方案

    Jenkins-2.204.1 版本 创建jenkins用户时,没填full name,且选择了使用系统的admin登录或者是admin登录只是改了admin的登录密码导致登录不上去(Invalid ...

  8. 【月光宝盒get√】用时间置换空间,聊聊稀疏数组的那些事儿

    背景 数据结构是指带有结构特性的数据元素的集合.在数据结构中,数据之间通过一定的组织结构关联在一起,便于计算机存储和使用.从大类划分,数据结构可以分为线性结构和非线性结构,适用于不同的应用场景. 线性 ...

  9. Java类加载器概述

    Java类加载器概述 Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由Java 应用开发人员编写的. 系统提供的类加载器 引导类加载器 它用来加载 Java 的核心库,是用原生 ...

  10. 改头换面为哪般,最像Android的Windows——Win11升级安装体验

    在过完了十一小长假之后,各位打工人.学僧党可期待的不仅仅是新一轮的工作,Windows11也在10月5日悄悄正式发布,正式版已经面向MSDN订阅用户开放下载. 作为微软金牌合作伙伴,本葡萄已在第一时间 ...