史上最为详细的javascript继承(推荐)


Posted in Javascript onMay 18, 2019

前言

为大家分享js中最常见最详细的继承方式,接下来将一下面的几个维度进行展示说明
文章有点长,请耐心阅读?,有什么错误理解的地方希望留言指出来

  1. 产生原因
  2. 代码实现
  3. 基本原理
  4. 语言实现
  5. 场景优点
  6. 缺点

继承方式

  1. 原型链继承
  2. 借用构造函数模式继承
  3. 组合继承
  4. 原型式继承
  5. 寄生式继承
  6. 寄生组合

原型链继承
相信小伙伴们都知道到原型链继承(ECMAScript 中描述了原型链的概念,并将原型链作为实现继承的主要方法),因为原型链继承非常的强大,但是也有它的缺点,接下来咱们就按照上面的维度看看原型链继承到底是什么鬼
代码实现:(需要两个构造函数来完成一个原型链继承)

// SuperType 构造函数称为超类
 function SuperType (){
   this.name='super';
   this.friend=[];
   this.property = true; 
}
SuperType.prototype.getName=function(){
  return this.name;
}
SuperType.prototype.getSuperValue = function(){
 return this.property;
}; 
// SubType 构造函数称为子类
function SubType(name,age){
  this.name=name;
  this.age=age;
  this.subproperty = false; 
}
SubType.prototype=new SuperType();
SubType.prototype.constrcutor=SubType;
SubType.prototype.getAge=function(){
  return this.age;
}
SubType.prototype.getSubValue = function (){
 return this.subproperty;
}; 
var child = new SubType('shiny',12);
console.log(child.getName)//shiny
console.log(child.getAge())//12

图解部分 属性

史上最为详细的javascript继承(推荐)

基本原理

使用类似作用域的原型链,进行继承查找

语言实现

定义两个构造函数,分别为父类(SuperType)、子类(SubType),为了实现子类能够使用父类的属性(本身和原型上面的属性)。重写子类的原型,让子类的原型指向父类实例,这样子类的构造函数就是父类的实例地址,实现子类可以使用父类的本身和原型上的属性

优点

子类可以通过原型链的查找,实现父类的属性公用与子类的实例

缺点  

  1. 一些引用数据操作的时候会出问题,两个实例会公用继承实例的引用数据类
  2. 谨慎定义方法,以免定义方法也继承对象原型的方法重名
  3. 无法直接给父级构造函数使用参数

借用构造函数模式继承
虽然原型链继承很强大但是也有他的缺点,借用构造函数继承可以解决原型链继承的缺点,开线面的解释
代码实现:

// 把父类当中一个函数使用
function SuperType(name){
this.name=name
this.friend=['a','b']
}
SuperType.prototype.getFriend=function(){
 return this.firend
}
function SubType(name){
 // 执行父类函数
 SuperType.call(this,name);
}
var child = new SubType('shiny')
var childRed = new SubType('red')
console.log(child.name)//shiny
console.log(childRed.name)//red
child.firend.push('c')
console.log(child.friend)//a,b,c
console.log(childRed.friend)//a,b
console.log(childRed.getFriend)//undefined

基本原理

使用call apply方法,通过执行方法修改tihs (上下文),是的父级的this变成子类实例的this,这样每个实例都会得到父类的属性,实现引用属性备份

使用场景

父类中需要一些子类使用共享的引用类型,并且子类可能会操作父类共享的引用类型
但是父类的非this绑定的属性和方法是不可以使用的(放在父类prototype的属性和方法)

语言实现

不要把父类当中构造函数,当中一个函数来处理这样更容易理解,在子类的构造函数中借用父类函数通过修改this来执行,这样子类的实例包含父类的属性

优点

  1. 解决了原型链继承的 引用类型操作问题
  2. 解决了父类传递参数问题

缺点

  1. 仅仅使用借用构造函数模式继承,无法摆脱够着函数。方法在构造函数中定义复用不可谈
  2. 对于超类的原型定义的方法对于子类是不可使用的,子类的实例只是得到了父类的this绑定的属性
  3. 考虑到这些缺点,单独使用借用构造函数也是很少使用的

组合继承

上面的两种继承方式(原型链继承+借用构造函数继承),都有自己优缺点,但是他们不是很完美,下面解释一下组合继承

代码实现:

 

function SuperType(name){
  this.name=name;
  this.firend=['a','b']
}
SuperType.prototype.getName=function(){
  return this.name
}
function SubType(name,age){
  this.age=age;
  SuperType.call(this,name)
}
SubType.prototype=new SuperType();
SubType.prototype.constrcutor = SubType;
SubType.prototype.getAge=function(){
  return this.age
}
var childShiny=new SubType('shiny',23);
var childRed = new SubType('red',22);
childShiny.firend.push('c');
childRed.firend.push('d');
console.log(childShiny.getName());
console.log(childShiny.getAge());
console.log(childRed.getName());
console.log(childRed.getAge());
console.log(childRed.friend);//[a,b,d]
console.log(childShiny.friend);//[a,b,c]

 基本原理

使用原型链的继承实现,通过原型查找功能来满足原型链共享方法
使用借用构造函数方法,使用实例备份父类共享引用类型备份

使用场景

得到原型链继承和构造函数继承的优点,是被开发人员认可的一种继承方式,但是也有他的缺点
语言实现

定义两个构造函数,分别为父类(SuperType)、子类(SubType),为了实现子类能够使用父类的属性(本身和原型上面的属性)。重写子类的原型,让子类的原型指向父类实例,这样子类的构造函数就是父类的实例地址,实现子类可以使用父类的本身和原型上的属性
不要把父类当中构造函数,当中一个函数来处理这样更容易理解,在子类的构造函数中借用父类函数通过修改this来执行,这样子类的实例包含父类的属性

优点

  1. 解决了原型链继承引用类型的实例操作导致引用改变
  2. 解决了借构造函数继承方式的,父类原型子类实例可以使用

缺点

  1. 父类的构造函数被实例换了两次
  2. 实例会有父类的构造函数的一些this属性、子类的构造函数(prototype)上也有一份实例的上有的属性

原型式继承

话说上面的的组合继承不是已经被开发者认可了吗,原型式继承是啥?下面咱们看看原型式继承是什么样的。

代码实现:

1 function object(o){
 function F(){};
 F.prototype=o;
  return new F()
}
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var personShiny = object(person);
var personRed = object(person);
console.log(personShiny.name)//Nicholas
console.log(personRed.name)//Nicholas
personShiny.friends.push('red');
personRed.friends.push('shiny');
console.log(personShiny.friends)//["Shelby", "Court", "Van","red","shiny"]
//ECMAScript 5 通过新增 Object.create()方法规范化了原型式继承。这个方法接收两个参数:一
//个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。在传入一个参数的情况下,
//Object.create()与 object()方法的行为相同。
2 
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var personShiny = Object.create(person);
var personRed = Object.create(person);
console.log(personShiny.name)//Nicholas
console.log(personRed.name)//Nicholas
personShiny.friends.push('red');
personRed.friends.push('shiny');
console.log(personShiny.friends)//["Shelby", "Court", "Van","red","shiny"]

基本原理

通过Object.create()方法来创建一个有基础类的实例,这实例的__proto__指向基础类

使用场景

在不使用构造函数的情况下,只想让一个对象与另一个对象保持类似的情况下

语言实现

需要创建一个基础对象,作为一个新对象的基础对象,通过object方法或者Object.create方法处理得到一个新实例,这个新实例上的__proto__指向基础对象

优点

再不用创建构造函数的情况下,实现了原型链继承,代码量减少一部分

缺点

  1. 一些引用数据操作的时候会出问题,两个实例会公用继承实例的引用数据类
  2. 谨慎定义方法,以免定义方法也继承对象原型的方法重名
  3. 无法直接给父级构造函数使用参数

寄生继承

咱们看了上面的原型式继承,其实就是和原型链继承差别不大,只是省去了构造函数这一部,但是原型式继承也是有缺点的(不能够给备份的对象添加属性),下面寄生继承来解决。

代码实现:

// 和工厂模式非常类似,创建一个对象,增强一些功能并返回该对象
function createAnother(o){
  var clone = Object(o);
  clone.sayHi=function(){
   console.log('hi')
}
  return clone
}
var person = {
  name:'shiny',
  friends:['a','b']
}
var personShiny = createAnother(person);
console.log(personShiny.sayHi())//Ho

基本原理

备份一个对象,然后给备份的对象进行属性添加,并返回

使用场景

在考不使用构造函数的情况下实现继承,前面示
范继承模式时使用的 object()函数不是必需的;任何能够返回新对象的函数都适用于此模式

语言实现

类似构造函数,通过一个执行方法,里面创建一个对象,为该对象添加属性和方法,然后返回

优点

  1. 再不用创建构造函数的情况下,实现了原型链继承,代码量减少一部分
  2. 可以给备份的对象添加一些属性

缺点

类似构造函数一样,创建寄生的方法需要在clone对象上面添加一些想要的属性,这些属性是放在clone上面的一些私有的属性

寄生组合继承

咱们看了上面的组合继承看上去已经很完美了,但是也有缺点(父类被实例化两次、子类实例和子类的构造函数都有相同的属性),寄生组合就是来解决这些问题的

代码实现:

function inheritPrototype({SubType,SuperType}){
   const prototype = Object(SuperType.prototype);
   prototype.constrcutor=SubType;
   SubType.prototype=prototype;
}
function SuperType(name){
  this.name=name;
  this.friends=['a','b']
}
SuperType.prototype.getName=function(){
  return this.name;
}
function SubType(name,age){
  this.age=age;
  SuperType.call(this,name)
}
inheritPrototype({SubType,SuperType});
SubType.prototype.getAge=function(){
  return this.age
}
var SubTypeShiny = new SubType('Shiny',23);
SubTypeShiny .friends.push('c')
var SubTypeRed = new SubType('Red',21);
SubTypeRed .friends.push('d')
console.log(SubTypeShiny.getName())//Shiny
console.log(SubTypeShiny.getAge())//22
console.log(SubTypeShiny.friends)//['a','b','c']
console.log( SubTypeRed.getName())//Red
console.log( SubTypeRed.getAge())//21
console.log( SubTypeRed.friends)//['a','b','d']

基本原理

子类构造函数内通过call、apply方法进行修改父类构造函数的this和执行父类构造函数,使的子类的实例拥有父类构造函数的一些属性,
结合子类的原型修改成父类构造函数的原型,并把父类的原型的constructor指向子类构造函数

使用场景

在考不使用构造函数的情况下实现继承,前面示

范继承模式时使用的 object()函数不是必需的;任何能够返回新对象的函数都适用于此模式

语言实现

极度类似组合寄生方式,只是修改了子类原型链继承的方式,组合寄生是继承父类的实例,寄生组合寄生则是通过一子类的原型继承父类的原型,并把该原型的constructor指向子类构造函数

优点

  1. 在少一次实例化父类的情况下,实现了原型链继承和借用构造函数
  2. 减少了原型链查找的次数(子类直接继承超类的prototype,而不是父类的实例)

缺点

暂无

下面是组合继承和寄生组合继承的原型图对比

史上最为详细的javascript继承(推荐)

以上所述是小编给大家介绍的javascript继承详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
深入理解JavaScript系列(10) JavaScript核心(晋级高手必读篇)
Jan 15 Javascript
javascript仿qq界面的折叠菜单实现代码
Dec 12 Javascript
jquery创建表格(自动增加表格)代码分享
Dec 25 Javascript
js showModalDialog弹出窗口实例详解
Jan 07 Javascript
jquery实现ajax提交form表单的方法总结
Mar 03 Javascript
js实现基于正则表达式的轻量提示插件
Aug 29 Javascript
js添加事件的通用方法推荐
May 15 Javascript
利用原生JS与jQuery实现数字线性变化的动画
Feb 24 Javascript
Javascript中JSON数据分组优化实践及JS操作JSON总结
Dec 22 Javascript
微信小程序在线客服自动回复功能(基于node)
Jul 03 Javascript
Vue 动态路由的实现及 Springsecurity 按钮级别的权限控制
Sep 05 Javascript
一篇文章告诉你如何实现Vue前端分页和后端分页
Feb 18 Vue.js
微信小程序云开发如何使用npm安装依赖
May 18 #Javascript
vue路由中前进后退的一些事儿
May 18 #Javascript
如何写好一个vue组件,老夫的一年经验全在这了(推荐)
May 18 #Javascript
微信小程序云开发 生成带参小程序码流程
May 18 #Javascript
详解小程序开发经验:多页面数据同步
May 18 #Javascript
JavaScript实现星级评价效果
May 17 #Javascript
JavaScript实现美化滑块效果
May 17 #Javascript
You might like
世界上第一台立体声收音机
2021/03/01 无线电
我的论坛源代码(九)
2006/10/09 PHP
三个类概括PHP的五种设计模式
2012/09/05 PHP
php header功能的使用
2013/10/28 PHP
PHP设计模式之观察者模式(Observer)详细介绍和代码实例
2014/04/08 PHP
DOM基础及php读取xml内容操作的方法
2015/01/23 PHP
PHP不使用递归的无限级分类简单实例
2016/11/05 PHP
ThinkPHP5.0框架结合Swoole开发实现WebSocket在线聊天案例详解
2019/04/02 PHP
javascript 类定义的4种方法
2009/09/12 Javascript
JS 显示当前日期与时间的代码
2010/03/24 Javascript
jQuery创建DOM元素实例解析
2015/01/19 Javascript
jquery专业的导航菜单特效代码分享
2015/08/29 Javascript
jQuery事件委托之Safari
2016/07/05 Javascript
微信小程序五子棋游戏AI实现方法【附demo源码下载】
2019/02/20 Javascript
js中arguments对象的深入理解
2019/05/14 Javascript
Nodejs监控事件循环异常示例详解
2019/09/22 NodeJs
vue实现全匹配搜索列表内容
2019/09/26 Javascript
原生js实现购物车
2020/09/23 Javascript
[01:02:48]2018DOTA2亚洲邀请赛小组赛 A组加赛 Newbee vs Liquid
2018/04/03 DOTA
python 正则式使用心得
2009/05/07 Python
Python程序中使用SQLAlchemy时出现乱码的解决方案
2015/04/24 Python
使用python将mysql数据库的数据转换为json数据的方法
2019/07/01 Python
解决安装pyqt5之后无法打开spyder的问题
2019/12/13 Python
pytorch下使用LSTM神经网络写诗实例
2020/01/14 Python
Python loguru日志库之高效输出控制台日志和日志记录
2020/03/07 Python
Python datetime 如何处理时区信息
2020/09/02 Python
python 星号(*)的多种用途
2020/09/21 Python
Python使用struct处理二进制(pack和unpack用法)
2020/11/12 Python
Parfume Klik丹麦:香水网上商店
2018/07/10 全球购物
营销总经理岗位职责
2014/02/02 职场文书
低碳环保倡议书
2014/04/14 职场文书
政治学求职信
2014/06/03 职场文书
2014国庆节国旗下演讲稿(精选版)
2014/09/26 职场文书
员工升职自荐信
2015/03/27 职场文书
Java无向树分析 实现最小高度树
2022/04/09 Javascript
JavaScript前端面试扁平数据转tree与tree数据扁平化
2022/06/14 Javascript