史上最为详细的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 相关文章推荐
网页的标准,IMG不支持onload标签怎么办
Jun 29 Javascript
Javascript之文件操作
Mar 07 Javascript
date.parse在IE和FF中的区别
Jul 29 Javascript
jquery序列化表单以及回调函数的使用示例
Jul 02 Javascript
JavaScript中的console.group()函数详细介绍
Dec 29 Javascript
jQuery插件EnPlaceholder实现输入框提示文字
Jun 05 Javascript
Jquery Ajax Error 调试错误的技巧
Nov 20 Javascript
jquery横向纵向鼠标滚轮全屏切换
Feb 27 Javascript
原生js仿浏览器滚动条效果
Mar 02 Javascript
基于对象合并功能的实现示例
Oct 10 Javascript
Angular整合zTree的示例代码
Jan 24 Javascript
jQuery+css last-child实现选择最后一个子元素操作示例
Dec 10 jQuery
微信小程序云开发如何使用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
php 使用GD库为页面增加水印示例代码
2014/03/24 PHP
Prototype Date对象 学习
2009/07/12 Javascript
分析Node.js connect ECONNREFUSED错误
2013/04/09 Javascript
javascript结合Canvas 实现简易的圆形时钟
2015/03/11 Javascript
JS实现自动变换的菜单效果代码
2015/09/09 Javascript
轻松学习jQuery插件EasyUI EasyUI实现树形网络基本操作(2)
2015/11/30 Javascript
基于zepto的移动端轻量级日期插件--date_picker
2016/03/04 Javascript
BootStrap中Tab页签切换实例代码
2016/05/30 Javascript
Backbone中View之间传值的学习心得
2016/08/09 Javascript
js删除数组中的元素delete和splice的区别详解
2018/02/03 Javascript
VUE项目初建和常见问题总结
2019/09/12 Javascript
Vue实现图片与文字混输效果
2019/12/04 Javascript
[01:08:29]DOTA2-DPC中国联赛定级赛 RNG vs Aster BO3第一场 1月9日
2021/03/11 DOTA
Python异常处理总结
2014/08/15 Python
Python 搭建Web站点之Web服务器网关接口
2016/11/06 Python
详解python 发送邮件实例代码
2016/12/22 Python
python学习笔记之列表(list)与元组(tuple)详解
2017/11/23 Python
Python入门之后再看点什么好?
2018/03/05 Python
Python解析并读取PDF文件内容的方法
2018/05/08 Python
Python将字符串常量转化为变量方法总结
2019/03/17 Python
基于tensorflow for循环 while循环案例
2020/06/30 Python
Java爬虫技术框架之Heritrix框架详解
2020/07/22 Python
matplotlib 使用 plt.savefig() 输出图片去除旁边的空白区域
2021/01/05 Python
纽约和芝加哥当天送花:Ode à la Rose
2019/07/05 全球购物
Wolford法国官网:奥地利奢侈内衣品牌
2020/08/11 全球购物
delegate与普通函数的区别
2014/01/22 面试题
农行实习自我鉴定
2013/09/22 职场文书
应届毕业生应聘自荐信范文
2014/02/26 职场文书
机关单位人员学雷锋心得体会
2014/03/10 职场文书
2014年家长学校工作总结
2014/11/20 职场文书
2015年酒店服务员工作总结
2015/05/18 职场文书
安全教育培训心得体会
2016/01/15 职场文书
个人向公司借款协议书
2016/03/19 职场文书
低版本Druid连接池+MySQL驱动8.0导致线程阻塞、性能受限
2021/07/01 MySQL
微软Win11什么功能最惊艳? Windows11新功能特性汇总
2021/11/21 数码科技
javascript中Set、Map、WeakSet、WeakMap区别
2022/12/24 Javascript