JavaScript中的几种继承方法示例


Posted in Javascript onDecember 06, 2020

1.原型链继承

原理: 子类原型指向父类实例对象实现原型共享,即Son.prototype = new Father()。

这里先简单介绍下原型

js中每个对象都有一个__proto__属性,这个属性指向的就是该对象的原型。js中每个函数都有一个prototype属性,这个属性指向该函数作为构造函数调用时创建的实例的原型。原型对象上有一个constructor属性,指向创建该对象的构造函数,该属性不可枚举。

var obj = {};
obj.__proto__ === Object.prototype; //true
console.log(Object.prototype.constructor) // ƒ Object

当我们访问一个对象的属性或者方法时,如果找不到,则会通过原型向上寻找,若原型上也未找到,则会去原型的原型上面去找。比如我要调用obj.toString方法时,在自身并未找到toString方法,则会去原型上去寻找,即在Object.prototype上去寻找,找到后运行该方法。

var obj = {};
obj.toString();
obj.__proto__.toString(); //obj.__proto__和Object.prototype指向的是一个对象,自然就能访问Object.prototype上的toString方法啦

注意:原型链的终点是null,使用bind方法返回的函数没有prototype属性。

var obj = {};
function fn(){};
fn.bind(obj).prototype; // undefined
Object.prototype.__proto__; // null

原型链接继承

function Father(age){
 this.age = age;
 this.color = ['red','pink']
}
Father.prototype.sayHello = function(){
 console.log('hello')
} 
function Son(sex){
 this.sex = sex
}
console.log(Son.prototype.constructor) // ƒ Son
Son.prototype = new Father(15) // 原型链继承关键
var son = new Son('男')
son.color.push('black')
var son2 = new Son('女')
son.sayHello() // hello
son.sayHello === son2.sayHello //true
console.log(son2.color) // ['red','pink','black']
console.log(Son.prototype.constructor) // ƒ Father

可以看到通过原型链实现继承,原型上引用类型的值会被所有实例共享。子类的constructor指向会发生改变,而且在创建子类实例时不可以向父类构造函数传递参数。可以手动把子类constructor属性指回其构造函数。

//写法一
Son.prototype.constructor = Son // 这种写法有点缺点,它会让constructor属性变的可以枚举。

//写法二
Object.defineProperty(Son.prototype,'constructor',{
 enumerable:false, // 设置不可枚举
 value:Son
})

2.构造函数继承

原理:在子类构造函数中通过apply或者call调用父类构造函数来继承属性或方法。

function Father(name){
 this.color = ['red']
 this.sayHello = function(){
  console.log('hello')
 }
}
Father.prototype.sayName = function(){
 console.log('zs')
}
function Son(num,name){
 Father.call(this,name) //实现继承的关键代码
 this.num = num
}
var son = new Son(10,'zs')
var son2 = new Son(15,'ls')
son.color.push('pink')
console.log(son2.color) // ['red']
son.sayName() //报错 son.sayName is not a function
console.log(son.sayHello === son2.sayHello) //false

可以看出通过构造函数实现继承,解决了原型链继承不能向父类传参以及引用类型值共享的问题。但这种继承方法却不能访问父类构造函数原型上的方法和属性,而且定义在父类构造函数中的方法也不能复用。

3.组合式继承

组合继承,有时候也叫伪经典继承,它是将原型链继承和构造函数继承结合到一起的一种继承模式。实现思路是通过原型链实现对原型属性和方法的继承,通过借用构造函数实现对实例属性的继承。

function Father(name){
 this.color = ['red']
}
Father.prototype.sayName = function(){
 console.log('zs')
}
function Son(num,name){
 Father.call(this,name) //继承实例属性
 this.num = num
}
Son.prototype = new Father() //继承原型上属性
Son.prototype.constructor = Son
var son = new Son(10,'zs')
var son2 = new Son(15,'ls')
son.color.push('pink')
console.log(son.color,son2.color) //['red','pink'] ['red']
son.sayName() // zs

组合式继承避免了原型链继承和构造函数继承的缺点,融合了它们的优点,成为JavaScript中常用的一种继承模式。

4.寄生式继承

寄生式继承与工厂模式类似,一般用来继承对象。即创建一个封装继承的函数,在函数内部复制一份该对象,对复制的对象进行处理,返回复制的对象。

function createAnother(obj){
  var clone = Object.create(obj)
  clone.name = 'zs'
  clone.sayHello = function(){
   console.log('hello')
  }
  return clone
}
var obj = {age:15}
var newObj = createAnother(obj) // 15
console.log(newObj.name) // zs
newObj.sayHello() // hello

5.寄生组合式继承

前面说到过组合式继承是Javascript中最常用的继承模式,不过这种模式也有自己的不足,它会调用两次父类构造函数。第一次是在将子类原型指向父类实例的时候,第二次是在子类构造函数中调用的。

function Father(name){
  this.name = name
 }
 function Son(num,name){
  Father.call(this,name) // 第二次调用
 }
 Son.prototype = new Father('ls') // 第一次调用
 var son = new Son(10,'zs')
 console.log(son)

在第一次调用的时候,Son.prototype会继承name这个属性,第二次调用时,实例对象会继承name。当我们获取实例对象的name属性时因为实例对象上有该属性,所以是不会去原型上去寻找的,相当于实例对象上的name属性把原型上的name属性给屏蔽掉了,所以原型上的这个属性是多余的。

JavaScript中的几种继承方法示例

为了解决这个问题,就有了寄生组合式继承。主要思路就是创建一个函数完成原型链继承和constructor的指向问题,然后通过构造函数继承属性。

// 复制一个父类的原型指向,将子类的原型指向复制的父类原型,达到不用调用父类构造函数就能继承其原型上的方法的效果。
 function inherit(Sup,Sub){
  var prototype = Object.create(Sup.prototype)
  Sub.prototype = prototype
  prototype.constructor = Sub
 }
 function Father(name){
  this.name = name
 }
 function Son(name){
 Father.call(this,name)
 }
 inherit(Father,Son)
 var son = new Son('zs')
 console.log(son)

JavaScript中的几种继承方法示例

以上就是JavaScript中常用的几种继承方式啦。

到此这篇关于JavaScript中的几种继承方法的文章就介绍到这了,更多相关JavaScript继承方法内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
Jquery 绑定时间实现代码
May 03 Javascript
jQuery EasyUI API 中文文档 - ComboBox组合框
Oct 07 Javascript
Javascript图像处理—虚拟边缘介绍及使用方法
Dec 27 Javascript
JQuery操作单选按钮以及复选按钮示例
Sep 23 Javascript
浅析JavaScript原型继承的陷阱
Dec 03 Javascript
jQuery遍历DOM的父级元素、子级元素和同级元素的方法总结
Jul 07 Javascript
JavaScript中for循环的几种写法与效率总结
Feb 03 Javascript
在vscode中统一vue编码风格的方法
Feb 22 Javascript
详解使用create-react-app添加css modules、sasss和antd
Jul 31 Javascript
Javascript的this详解
Mar 23 Javascript
vue+element-ui JYAdmin后台管理系统模板解析
Jul 28 Javascript
vue移动端下拉刷新和上滑加载
Oct 27 Javascript
js调用网络摄像头的方法
Dec 05 #Javascript
浅谈Vue使用Elementui修改默认的最快方法
Dec 05 #Vue.js
vue+element_ui上传文件,并传递额外参数操作
Dec 05 #Vue.js
JavaScript实现浏览器网页自动滚动并点击的示例代码
Dec 05 #Javascript
解决vue下载后台传过来的乱码流的问题
Dec 05 #Vue.js
js获取图片的base64编码并压缩
Dec 05 #Javascript
js重写alert事件(避免alert弹框标题出现网址)
Dec 04 #Javascript
You might like
php xml常用函数的集合(比较详细)
2013/06/06 PHP
php项目中百度 UEditor 简单安装调试和调用
2015/07/15 PHP
thinkPHP导出csv文件及用表格输出excel的方法
2015/12/30 PHP
thinkPHP查询方式小结
2016/01/09 PHP
php封装的图片(缩略图)处理类完整实例
2016/10/19 PHP
PHP实现15位身份证号转18位的方法分析
2019/10/16 PHP
Laravel 5.5 实现禁用用户注册示例
2019/10/24 PHP
js变量作用域及可访问性的探讨
2006/11/23 Javascript
js confirm()方法的使用方法实例
2013/07/13 Javascript
Extjs中RowExpander控件的默认展开问题示例探讨
2014/01/24 Javascript
js网页滚动条滚动事件实例分析
2015/05/05 Javascript
Javascript对象字面量的理解
2016/06/22 Javascript
使用jQuery实现一个类似GridView的编辑,更新,取消和删除的功能
2017/03/15 Javascript
js学习总结_选项卡封装(实例讲解)
2017/07/13 Javascript
AngularJS select设置默认值的实现方法
2017/08/25 Javascript
JS实现可用滑块滑动的缓动图代码
2019/09/01 Javascript
JavaScript设计模式---单例模式详解【四种基本形式】
2020/05/16 Javascript
python实现爬虫下载漫画示例
2014/02/16 Python
Python实现将罗马数字转换成普通阿拉伯数字的方法
2017/04/19 Python
pygame 精灵的行走及二段跳的实现方法(必看篇)
2017/07/10 Python
Python实现微信自动好友验证,自动回复,发送群聊链接方法
2019/02/21 Python
Django ORM 聚合查询和分组查询实现详解
2019/08/09 Python
keras 两种训练模型方式详解fit和fit_generator(节省内存)
2020/07/03 Python
程序运行正确, 但退出时却"core dump"了,怎么回事
2014/02/19 面试题
满月酒答谢词
2014/01/14 职场文书
大学军训感想
2014/02/12 职场文书
班组长岗位职责
2014/03/03 职场文书
奠基仪式策划方案
2014/05/15 职场文书
工资收入证明样本(5篇)
2014/09/16 职场文书
共产党员批评与自我批评
2014/10/15 职场文书
2014年销售人员工作总结
2014/11/27 职场文书
前台接待岗位职责
2015/02/03 职场文书
晚会开场白和结束语
2015/05/29 职场文书
公司老总年会致辞
2015/07/30 职场文书
Python代码,能玩30多款童年游戏!这些有几个是你玩过的
2021/04/27 Python
HTML5页面音频自动播放的实现方式
2021/06/21 HTML / CSS