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 相关文章推荐
jQuery1.9.1针对checkbox的调整方法(prop)
May 01 Javascript
jQuery 获取跨域XML(RSS)数据的相关总结分析
May 18 Javascript
让DIV的滚动条自动滚动到最底部的3种方法(推荐)
Sep 24 Javascript
简单谈谈React中的路由系统
Jul 25 Javascript
VUE页面中加载外部HTML的示例代码
Sep 20 Javascript
JS实现导出Excel的五种方法详解【附源码下载】
Mar 15 Javascript
利用Decorator如何控制Koa路由详解
Jun 26 Javascript
详解jQuery获取特殊属性的值以及设置内容
Nov 14 jQuery
JavaScript数组去重的方法总结【12种方法,号称史上最全】
Feb 28 Javascript
全面分析JavaScript 继承
May 30 Javascript
解决vue+router路由跳转不起作用的一项原因
Jul 19 Javascript
OpenLayer学习之自定义测量控件
Sep 28 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 项目的方法
2007/01/02 PHP
php strtotime 函数UNIX时间戳
2009/01/14 PHP
PHP的SQL注入实现(测试代码安全不错)
2011/02/27 PHP
供参考的 php 学习提高路线分享
2011/10/23 PHP
php数组函数序列之array_push() 数组尾部添加一个或多个元素(入栈),返回新长度。
2011/11/07 PHP
ThinkPHP中redirect用法分析
2014/12/05 PHP
php将图片保存入mysql数据库失败的解决方法
2014/12/27 PHP
PHP中for循环与foreach的区别
2017/03/06 PHP
JS应用之禁止抓屏、复制、打印
2008/02/21 Javascript
File文件控件,选中文件(图片,flash,视频)即立即预览显示
2009/04/09 Javascript
读jQuery之四(优雅的迭代)
2011/06/20 Javascript
SOSO地图API使用(一)在地图上画圆实现思路与代码
2013/01/15 Javascript
setTimeout内不支持jquery的选择器的解决方案
2015/04/28 Javascript
JavaScript 数组中最大最小值
2016/06/05 Javascript
Angularjs CURD 详解及实例代码
2016/09/14 Javascript
微信小程序 wx.uploadFile无法上传解决办法
2016/12/14 Javascript
微信小程序 增、删、改、查操作实例详解
2017/01/13 Javascript
借助node实战JSONP跨域实例
2017/03/30 Javascript
JavaScript使用readAsDataURL读取图像文件
2017/05/10 Javascript
vue-router 导航钩子的具体使用方法
2017/08/31 Javascript
JavaScript 数组的进化与性能分析
2017/09/18 Javascript
jQuery访问浏览器本地存储cookie、localStorage和sessionStorage的基本用法
2017/10/20 jQuery
如何更好的编写js async函数
2018/05/13 Javascript
Vue组件Draggable实现拖拽功能
2018/12/01 Javascript
详解如何使用微信小程序云函数发送短信验证码
2019/03/13 Javascript
基于脚手架创建Vue项目实现步骤详解
2020/08/03 Javascript
vue页面引入three.js实现3d动画场景操作
2020/08/10 Javascript
[02:06]2018完美世界全国高校联赛秋季赛开始报名(附彩蛋)
2018/09/03 DOTA
[50:48]LGD vs CHAOS 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
Django中的Model操作表的实现
2018/07/24 Python
python 浮点数四舍五入需要注意的地方
2020/08/18 Python
模具专业毕业生自荐书范文
2014/02/19 职场文书
精神文明建设汇报材料
2014/12/24 职场文书
优秀班组事迹材料
2014/12/24 职场文书
复制别人的成功真的会成功吗?
2019/10/17 职场文书
JS不要再到处使用绝对等于运算符了
2021/04/30 Javascript