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 相关文章推荐
jQuery 工具函数学习资料
Apr 29 Javascript
JS验证控制输入中英文字节长度(input、textarea等)具体实例
Jun 21 Javascript
在页面加载完成后通过jquery给多个span赋值
May 21 Javascript
javascript实现textarea中tab键的缩排处理方法
Jun 26 Javascript
jQuery实现鼠标选文字发新浪微博的方法
Apr 02 Javascript
javascript类型系统_正则表达式RegExp类型详解
Jun 24 Javascript
jquery实现简单的瀑布流布局
Dec 11 Javascript
jQuery插件FusionWidgets实现的Cylinder图效果示例【附demo源码】
Mar 23 jQuery
浅析vue中的provide / inject 有什么用处
Nov 10 Javascript
解决vue项目input输入框双向绑定数据不实时生效问题
Aug 05 Javascript
微信小程序实现倒计时功能
Nov 19 Javascript
javascript的var与let,const之间的区别详解
Feb 18 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
深入了解 register_globals (附register_globals=off 网站打不开的解决方法)
2012/06/27 PHP
PHP Error与Logging函数的深入理解
2013/06/03 PHP
php利用cookies实现购物车的方法
2014/12/10 PHP
PHP数组相加操作及与array_merge的区别浅析
2016/11/26 PHP
Zend Framework入门教程之Zend_Session会话操作详解
2016/12/08 PHP
php使用正则表达式获取字符串中的URL
2016/12/29 PHP
PHP实现可精确验证身份证号码的工具类示例
2018/05/31 PHP
java解析json方法总结
2019/05/16 PHP
ExtJs设置GridPanel表格文本垂直居中示例
2013/07/15 Javascript
什么是cookie?js手动创建和存储cookie
2014/05/27 Javascript
javascript实现禁止右键和F12查看源代码
2014/12/26 Javascript
NodeJS学习笔记之(Url,QueryString,Path)模块
2015/01/13 NodeJs
轻松使用jQuery双向select控件Bootstrap Dual Listbox
2015/12/13 Javascript
基于JavaScript实现快速转换文本语言(繁体中文和简体中文)
2016/03/07 Javascript
详解Node.js模块间共享数据库连接的方法
2016/05/24 Javascript
angular route中使用resolve在uglify压缩后问题解决
2016/09/21 Javascript
基于jquery实现弹幕效果
2016/09/29 Javascript
vue使用 better-scroll的参数和方法详解
2018/01/25 Javascript
vue中手机号,邮箱正则验证以及60s发送验证码的实例
2018/03/16 Javascript
详解promise.then,process.nextTick, setTimeout 以及 setImmediate的执行顺序
2018/11/21 Javascript
vue中可编辑树状表格的实现代码
2020/10/31 Javascript
[39:11]DOTA2上海特级锦标赛C组资格赛#2 LGD VS Newbee第二局
2016/02/28 DOTA
Python爬虫设置代理IP的方法(爬虫技巧)
2018/03/04 Python
PyQt5每天必学之拖放事件
2020/08/27 Python
PyCharm配置anaconda环境的步骤详解
2020/07/31 Python
Python如何读写字节数据
2020/08/05 Python
华润集团网上药店:健一网
2016/09/19 全球购物
美国著名手表网站:Timepiece
2017/11/15 全球购物
Big Green Smile法国:领先的英国有机和天然产品在线商店
2021/01/02 全球购物
技校个人求职信范文
2014/01/25 职场文书
作弊检讨书1000字
2014/02/01 职场文书
酒店优秀员工事迹材料
2014/06/02 职场文书
幼儿老师求职信
2014/06/30 职场文书
监理中标通知书
2015/04/16 职场文书
如何解决springcloud feign 首次调用100%失败的问题
2021/06/23 Java/Android
vue elementUI表格控制对应列
2022/04/13 Vue.js