javaScript(ES5)中想方设法继承家产的方式详解
目录
- 前言
- 一、原型链继承
- 原型链继承的概念
- 原型链继承的不足
- 二、借用构造函数继承
- 借用构造函数继承的概念
- 利用构造函数继承的不足
- 三、组合继承(原型链继承+构造函数继承)
- 组合继承的概念
- 组合继承的缺陷
- 四、寄生组合性继承
- 寄生组合性继承的概念
- 寄生组合性继承的优点
- 多重继承
- 多重继承的概念
- 总结
前言
在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"]
原型链继承的不足
原型链继承一共有以下两个问题:
- 原型链继承中,子类的实例对象会共享父类的
实例对象属性
,当父类的实例对象属性是引用数据类型
时,一旦子类中的实例对象对其修改,则子类所有的实例对象所继承的相应属性值都会发现改变
。
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!"]
- 当创建子类的实例对象时,
无法传参
给父类,也就无法使用父类的构造函数
。
二、借用构造函数继承
借用构造函数继承的概念
为了解决使用原型链继承
无法在创建子类实例对象时,无法传参给父类
的缺陷,因此我们使用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)中想方设法继承家产的方式详解相关推荐
- js继承的六种方式详解--认真看完你就会了
今天 主要来研究一下继承这个东西 继承 共分为六种继承方式: 原型链继承 盗用构造函数继承 组合继承 实例继承(原型式继承) 寄生式继承 寄生式组合继承 原型链继承 原型链继承是ES主要继承方法,其中 ...
- asp.net Session在web.config中的三种配置方式——详解
这段代码就是设置session在web.config中的存储方式. < sessionState mode="Off|InProc|StateServer|SQLServer" ...
- @AspectJ中的几种通知方式详解
本文来详细说下@AspectJ中的几种通知方式 文章目录 概述 通知方式说明 一个例子 本文小结 概述 当Spring 2.0发布以后,Spring AOP增加了新的使用方式,Spring AOP集成 ...
- Unity3D中UGUI的RectTransform对齐方式详解
https://www.jianshu.com/p/831e2dd7c546 https://www.jianshu.com/p/4592bf809c8b 在Unity自带的UGUI中,RectTra ...
- java clone方法_干货满满:Java中创建对象的五种方式详解
通常来说,对象具有状态和行为,变量用来表明对象的状态,方法表明对象所具有的行为. 作为Java开发者,我们通常都是使用依赖管理系统,比如Spring去创建Java对象,但使用管理系统创建对象并不是唯一 ...
- java中三种基本循环方式详解
#博学谷IT学习技术支持# Java循环for,while和do-while 简述:如果对于同一种操作需要执行多次的话,就要使用到循环结构.它可以大大简化代码的书写量,让我们的开发更便捷. 例如:打印 ...
- php中 继承中的概念,JavaScript_JavaScript中的继承方式详解,js继承的概念
js里常用的如下 - phpStudy...
JavaScript中的继承方式详解 js继承的概念 js里常用的如下两种继承方式: 原型链继承(对象间的继承) 类式继承(构造函数间的继承) 由于js不像java那样是真正面向对象的语言,js是基于 ...
- 7种方法实现ES5中的继承
7种方法实现ES5中的继承 1.借用构造函数继承父类属性 步骤 实现示例 优缺点 2.利用原型对象继承父类方法 步骤 实现示例 优缺点 3.组合继承 步骤 实现示例 优缺点 4.寄生式继承 步骤 实现 ...
- C++的三种继承方式详解
文章目录 @[toc] C++的三种继承方式详解以及区别 前言 一.public继承 二.protected继承 三.private继承 四.三者区别 五.总结 后话 C++的三种继承方式详解以及区别 ...
最新文章
- x86汇编语言从实模式百度云_Intel x86 CPU 32位保护模式杂谈之任务切换 上
- php dropdownlist,遇到dropdownlist
- linux终端刷新网络命令,在Ubuntu Linux操作系统中重新启动网络的方法
- java解析json_JAVA解析JSON数据
- 【类】变量复用,函数复用
- ubuntu完全清除mysql残留文件和配置
- 2019重庆对口高职计算机类分数排名,重庆2019高职分类考试分数线公布
- spark dataframe常用操作集锦
- 基于AI的恶意软件分析技术(3)
- 实现fashion_minst服装图像分类
- 如何在数据库mysql中储存图片
- Java版数据结构之单向链表
- Flask数据库_filter过滤器的使用
- 盛世昊通全新升级,引领智慧新经济
- 解决火绒提示helper_haozip.exe文件是病毒威胁
- 新手零基础:飞桨代码中关于图片路径读取和资源解压报错
- 服务自省,Dubbo面向了应用级
- Apache的虚拟主机配置和伪静态操作
- Python BDD 框架之lettuce
- XML Schema教程