js 组合继承详解
前言
首先学习继承之前,要对原型链有一定程度的了解。
不了解可以去先阅读我另一篇文章,里面对原型链有一个较为详细的说明: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);
特点:
- 两个实例对象都没有fatherAttr属性,但是因为父类的实例会拥有fatherAttr属性,且现在父类的实例作为child的原型,根据原型链,他们可以共享到自己的构造函数child的原型上的属性。(测试1)
- 因为只有一个父类的实例作为他们的原型,所以所有实例共享了一个原型上的属性fatherAttr,当原型上的属性作为引用类型时,此处是数组,test1添加一个新内容会导致test2上的fatherAttr也改变了。(测试2)(
缺点
)- child构造函数不能传递入参。(
缺点
)- 实例可以访问到父类的原型上的属性,因此可以把可复用方法定义在父类原型上。(测试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);
特点:
- 两个实例对象都拥有了拷贝来的fatherAttr属性,所以没有共享属性,创造一个实例就得拷贝一次父类的所有属性,且因为不能继承父类原型,所以方法不能复用,被迫拷贝方法。(测试1)(
缺点
)- test1添加一个新内容只是改变了test1自己的属性,不会影响到test2。(测试2)
- child构造函数可以传递参数,定制自己的属性。(测试1)
- 实例不能继承父类的原型上的属性。(测试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);
特点:
- 两个实例对象都拥有了拷贝来的fatherAttr属性,创造一个实例就得拷贝一次父类的所有属性(构造函数继承特点,测试1),但是能访问父类原型,可以把复用方法定义在父类原型上。(原型链继承特点,测试1)
- test1添加一个新内容只是改变了test1自己的属性,不会影响到test2。(构造函数继承特点,测试2)
- child构造函数可以传递参数,定制自己的属性。(构造函数继承特点,测试1)
- 实例能继承父类的原型上的属性。(原型链继承特点,测试3)
- 调用了两次父类的构造函数,生成两份实例,创建子类原型链一次,用子类创建实例时,子类内部里面一次,第二次覆盖了第一次。(
缺点
)- 因为调用两次父类构造函数,如果用delete删除实例上拷贝来的fatherAttr属性,实例仍然拥有隐式原型指向的父类实例上的fatherAttr属性。(原型链继承特点,测试4)(
缺点
)
js 组合继承详解的更多相关文章
- 《Node.js开发实战详解》学习笔记
<Node.js开发实战详解>学习笔记 ——持续更新中 一.NodeJS设计模式 1 . 单例模式 顾名思义,单例就是保证一个类只有一个实例,实现的方法是,先判断实例是否存在,如果存在则直 ...
- Js apply 方法 详解
Js apply方法详解 我在一开始看到JavaScript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...
- ES6,ES2105核心功能一览,js新特性详解
ES6,ES2105核心功能一览,js新特性详解 过去几年 JavaScript 发生了很大的变化.ES6(ECMAScript 6.ES2105)是 JavaScript 语言的新标准,2015 年 ...
- Js apply()使用详解
Js apply方法详解 我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...
- Js apply方法详解,及其apply()方法的妙用
Js apply方法详解 我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...
- [原创]JavaScript继承详解
原文链接:http://www.cnblogs.com/sanshi/archive/2009/07/08/1519036.html 面向对象与基于对象 几乎每个开发人员都有面向对象语言(比如C++. ...
- Vue.js 数据绑定语法详解
Vue.js 数据绑定语法详解 一.总结 一句话总结:Vue.js 的模板是基于 DOM 实现的.这意味着所有的 Vue.js 模板都是可解析的有效的 HTML,且通过一些特殊的特性做了增强.Vue ...
- “全栈2019”Java第九十九章:局部内部类与继承详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- JS hashMap实例详解
链接:http://www.jb51.net/article/85111.htm JS hashMap实例详解 作者:囧侠 字体:[增加 减小] 类型:转载 时间:2016-05-26我要评论 这篇文 ...
随机推荐
- 简单了解Phar代码打包工具的使用
简单了解Phar代码打包工具的使用 Phar 是在 PHP5 之后提供的一种类似于将代码打包的工具.本质上是想依照 Java 的 Jar 文件那种形式的代码包,不过本身由于 PHP 是不编译的,所以这 ...
- linux新安装了php,但是使用mysqli连接数据库一直超时
centos7+mysql5.5+php5.6+nginx mysql php nginx都安装完成,然后启动了,网站也运行, 但是php文件中使用mysqli_connect时一直超时,有时也报错, ...
- php无限分类 构建树形结构
<?php class Classification { const PARENT_ID = 'parentid'; const ID = 'id'; const CHILDREN = 'chi ...
- centos7.0 能ping通ip 无法ping通域名处理方法
第一步: 检查 vi /etc/sysconfig/network-scripts/ifcfg-eth0 查看网卡配置里的dns是否与 vi /etc/resolv.conf 的 nameser ...
- MyBatis Plus 批量数据插入功能,yyds!
最近 Review 小伙伴代码的时候,发现了一个小小的问题,小伙伴竟然在 for 循环中进行了 insert (插入)数据库的操作,这就会导致每次循环时都会进行连接.插入.断开连接的操作,从而导致一定 ...
- [科技]Loj#6564-最长公共子序列【bitset】
正题 题目链接:https://loj.ac/p/6564 题目大意 给两个序列\(a,b\)求它们的最长公共子序列. \(1\leq n,m,a_i,b_i\leq 7\times 10^4\) 解 ...
- P3309-[SDOI2014]向量集【线段树,凸壳】
正题 题目链接:https://www.luogu.com.cn/problem/P3309 题目大意 \(n\)个操作 在序列末尾加入一个向量\((x,y)\) 询问加入的第\(l\sim r\)个 ...
- P5956-[POI2017]Podzielno【数学】
正题 题目链接:https://www.luogu.com.cn/problem/P5956 题目大意 \(B\)进制下,给出序列\(a\),\(a_i\)表示数字\(i\)有多少个.求一个最大的\( ...
- 牛客练习赛71E-神奇的迷宫【点分治,NTT】
正题 题目链接:https://ac.nowcoder.com/acm/contest/7745/E 题目大意 给出\(n\)个点的一棵树,每个点有一个选择权重\(a_i\)(有\(\frac{a_i ...
- Python实现一个简单三层神经网络的搭建并测试
python实现一个简单三层神经网络的搭建(有代码) 废话不多说了,直接步入正题,一个完整的神经网络一般由三层构成:输入层,隐藏层(可以有多层)和输出层.本文所构建的神经网络隐藏层只有一层.一个神经网 ...