js中实现继承的五种方法


Posted in Javascript onJanuary 25, 2021

借用构造函数

这种技术的基本思想很简单,就是在子类型构造函数的内部调用超类型的构造函数。另外,函数只不过是在特定环境中执行代码的对象,因此通过使用apply()和call()方法也可以在新创建的对象上执行构造函数。

function Box(name){
 this.name = name
}
Box.prototype.age = 18

function Desk(name){
 Box.call(this, name) // 对象冒充,对象冒充只能继承构造里的信息
}

var desk = new Desk('ccc')
console.log(desk.name)   // --> ccc
console.log(desk.age)    // --> undefined

从中可以看到,继承来的只有实例属性,而原型上的属性是访问不到的。这种模式解决了两个问题,就是可以传参,可以继承,但是没有原型,就没有办法复用。

组合继承

function Box(name){
 this.name = name
}
Box.prototype.run = function (){
 console.log(this.name + '正在运行...')
}

function Desk(name){
 Box.call(this, name) // 对象冒充
}

Desk.prototype = new Box() // 原型链

var desk = new Desk('ccc')
console.log(desk.name)   // --> ccc
desk.run()         // --> ccc正在运行...

这种继承方式的思路是:用使用原型链的方式来实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。

原型式继承

原型式继承:是借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。讲到这里必须得提到一个人,道格拉斯·克罗克福德在2006年写的一篇文章《Prototype inheritance in Javascript》(Javascript中的原型式继承)中给出了一个方法:

function object(o) {   //传递一个字面量函数
 function F(){}     //创建一个构造函数
 F.prototype = o;    //把字面量函数赋值给构造函数的原型
 return new F()     //最终返回出实例化的构造函数
}

看如下的例子:

function obj(o) {
 function F (){}
 F.prototype = o;
 return new F()
}

var box = {
 name: 'ccc',
 age: 18,
 family: ['哥哥','姐姐']
}

var box1 = obj(box)
console.log(box1.name)   // --> ccc
box1.family.push('妹妹')
console.log(box1.family)  // --> ["哥哥", "姐姐", "妹妹"]

var box2 = obj(box)
console.log(box2.family)  // --> ["哥哥", "姐姐", "妹妹"]

因为上述的代码的实现逻辑跟原型链继承很类似,所以里面的引用数组,即family属性被共享了。

寄生式继承

function obj(o) {
 function F (){}
 F.prototype = o;
 return new F()
}
function create(o){
 var clone = obj(o)   // 通过调用函数创建一个新对象
 clone.sayName = function(){   // 以某种方式来增强这个对象
  console.log('hi')
 }
 return clone   // 返回这个对象
}

var person = {
 name: 'ccc',
 friends: ['aa','bb']
}

var anotherPerson = create(person)
anotherPerson.sayName()   // --> hi

这个例子中的代码基于person返回一个新对象————anotherPerson。新对象不仅具有person的所有属性和方法,而且还有自己的sayHi()方法。在主要考虑对象而不是自定义类型和构造函数的情况下,寄生式继承也是一种有用的模式。使用寄生式继承来为对象添加函数,会由于不能做到函数复用而降低效率,这一点与构造函数模式类似。

寄生组合式继承

前面说过,组合继承是Javascript最常用的继承模式,不过,它也有自己的不足。组合继承最大的问题就是无论什么情况下,都会调用过两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。没错,子类型最终会包含超类型对象的全部实例属性,但我们不得不在调用子类型构造函数时重写这些属性,再来看一下下面的例子:

function SuperType(name){
 this.name = name;
 this.colors = ['red','black']
}
SuperType.prototype.sayName = function (){
 console.log(this.name)
}
function SubType(name, age){
 SuperType.call(this, name) // 第二次调用SuperType
 this.age = age
}

SubType.prototype = new SuperType() // 第一次调用SuperType
SubType.prototype.constructor = SubType
SubType.prototype.sayAge = function (){
 console.log(this.age)
}

第一次调用SuperType构造函数时,SubType.prototype会得到两个属性:name和colors。他们都是SuperType的实例属性,只不过现在位于SubType的原型中。当调用SubType构造函数时,又会调用一次SuperType构造函数,这个一次又在新对象上创建了实例属性name和colors。于是,这两个属性就屏蔽了原型中的两个同名属性。即有两组name和colors属性:一组在实例上,一组在原型上。这就是调用两次SuperType构造函数的结果。解决这个问题的方法就是————寄生组合式继承。
所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。其背后的基本思路是:不必为了制定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。寄生组合式继承的基本模式如下:

function object(o) {
 function F (){}
 F.prototype = o;
 return new F()
}
function inheritPtototype(subType, superType){
 var prototype = object(superType.prototype) // 创建对象
 prototype.constructor = subType       // 增强对象
 subType.prototype = prototype        // 指定对象
}

function SuperType(name){
 this.name = name
 this.colors = ['red', 'white']
}

SuperType.prototype.sayName = function(){
 console.log(this.name)
}

function SubType(name,age){
 SuperType.call(this,name)
 this.age = age
}

inheritPtototype(SubType, SuperType)

SubType.prototype.sayAge = function(){
 console.log(this.age)
}

var instance = new SubType('ccc', 18)

instance.sayName()   // --> ccc
instance.sayAge()    // --> 18
console.log(instance)

控制台打印出的结构:

js中实现继承的五种方法

详细的图解:

js中实现继承的五种方法

这个例子的高效率提现在它值调用了一次SuperType构造函数,并且因此避免了在SubType.prototype上面创建不必要的、多余的属性。与此同时,原型链还能保持不变;因此,还能够正常使用instanceof和isPrototypeOf()。这也是很多大厂用的继承方式。

以上就是js中实现继承的五种方法的详细内容,更多关于js 实现继承的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
使用POST方式弹出窗口的两种方法示例介绍
Jan 29 Javascript
DIV始终居中的js代码
Feb 17 Javascript
javascript函数重载解决方案分享
Feb 19 Javascript
jQuery中hide()方法用法实例
Dec 24 Javascript
jQuery实现Div拖动+键盘控制综合效果的方法
Mar 10 Javascript
轻松实现javascript图片轮播特效
Jan 13 Javascript
js+canvas绘制矩形的方法
Jan 28 Javascript
jQuery实现倒计时(倒计时年月日可自己输入)
Dec 02 Javascript
浅谈vue中使用图片懒加载vue-lazyload插件详细指南
Oct 23 Javascript
初学者AngularJS的环境搭建过程
Oct 27 Javascript
javascript操作元素的常见方法小结
Nov 13 Javascript
vue 动态添加class,三个以上的条件做判断方式
Nov 02 Javascript
Vue中的nextTick作用和几个简单的使用场景
Jan 25 #Vue.js
Vue使用Ref跨层级获取组件的步骤
Jan 25 #Vue.js
javascript实现点击产生随机图形
Jan 25 #Javascript
如何在Vue项目中添加接口监听遮罩
Jan 25 #Vue.js
json.stringify()与json.parse()的区别以及用处
Jan 25 #Javascript
使用vue3重构拼图游戏的实现示例
Jan 25 #Vue.js
ReactRouter的实现方法
Jan 25 #Javascript
You might like
php下通过POST还是GET来传值
2008/06/05 PHP
php下连接ftp实现文件的上传、下载、删除文件实例代码
2010/06/03 PHP
php数组函数序列之array_values() 获取数组元素值的函数与方法
2011/10/30 PHP
php使用正则表达式进行字符串搜索的方法
2015/03/23 PHP
PHP实现的QQ空间g_tk加密算法
2015/07/09 PHP
php基于curl实现的股票信息查询类实例
2016/11/11 PHP
微信 getAccessToken方法详解及实例
2016/11/23 PHP
PHP实现微信提现功能(微信商城)
2019/11/21 PHP
深入理解JavaScript系列(6):S.O.L.I.D五大原则之单一职责SRP
2012/01/15 Javascript
JQuery操作iframe父页面与子页面的元素与方法(实例讲解)
2013/11/20 Javascript
使用js操作css实现js改变背景图片示例
2014/03/10 Javascript
每天一篇javascript学习小结(基础知识)
2015/11/10 Javascript
JS中使用apply方法通过不同数量的参数调用函数的方法
2016/05/31 Javascript
angularjs ocLazyLoad分步加载js文件实例
2017/01/17 Javascript
Vue.js鼠标悬浮更换图片功能
2017/05/17 Javascript
AngularJS表单验证功能分析
2017/05/26 Javascript
解决Vue 项目打包后favicon无法正常显示的问题
2018/09/01 Javascript
Vuex中的State使用介绍
2019/01/19 Javascript
JS函数动态传递参数的方法分析【基于arguments对象】
2019/06/05 Javascript
JS前端知识点 运算符优先级,URL编码与解码,String,Math,arguments操作整理总结
2019/06/27 Javascript
DatePickerDialog 自定义样式及使用全解
2019/07/09 Javascript
微信小程序image图片加载完成监听
2019/08/31 Javascript
vue.js的简单自动求和计算实例
2019/11/08 Javascript
如何解决jQuery 和其他JS库的冲突
2020/06/22 jQuery
解决Tensorflow安装成功,但在导入时报错的问题
2018/06/13 Python
解决pytorch多GPU训练保存的模型,在单GPU环境下加载出错问题
2020/06/23 Python
Django websocket原理及功能实现代码
2020/11/14 Python
课前三分钟演讲稿
2014/04/24 职场文书
大学生精神文明先进个人事迹材料
2014/05/02 职场文书
铣工实训报告
2014/11/05 职场文书
营销计划书范文
2015/01/17 职场文书
党小组意见范文
2015/06/08 职场文书
2016年万圣节家长开放日活动总结
2016/04/05 职场文书
导游词之鲁迅祖居
2019/10/17 职场文书
tomcat默认最大连接数及相关调整方法
2022/05/06 Servers
CSS中使用grid布局实现一套模板多种布局
2022/07/15 HTML / CSS