史上最为详细的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 相关文章推荐
jQuery源码分析-03构造jQuery对象-工具函数
Nov 14 Javascript
基于jquery库的tab新形式使用
Nov 16 Javascript
jquery 无限极下拉菜单的简单实例(精简浓缩版)
May 31 Javascript
使用JQuery选择HTML遍历函数的方法
Sep 17 Javascript
基于JavaScript实现焦点图轮播效果
Mar 27 Javascript
微信小程序后台解密用户数据实例详解
Jun 28 Javascript
Require.js的基本用法详解
Jul 03 Javascript
Vue学习笔记进阶篇之多元素及多组件过渡
Jul 19 Javascript
Nuxt配合Node在实际生产中的应用详解
Aug 07 Javascript
layui实现数据表格点击搜索功能
Mar 26 Javascript
vue组件 keep-alive 和 transition 使用详解
Oct 11 Javascript
JS深入学习之数组对象排序操作示例
May 01 Javascript
微信小程序云开发如何使用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实现的交通银行网银在线支付接口ECSHOP插件和使用例子
2014/05/10 PHP
windows7下安装php的php-ssh2扩展教程
2014/07/04 PHP
在Mac OS上搭建Nginx+PHP+MySQL开发环境的教程
2015/12/21 PHP
解析WordPress中函数钩子hook的作用及基本用法
2015/12/22 PHP
PHP编写文件多服务器同步程序
2016/07/02 PHP
php封装db类连接sqlite3数据库的方法实例
2017/12/19 PHP
Firefox 无法获取cssRules 的解决办法
2006/10/11 Javascript
jquery和javascript中如何将一元素的内容赋给另一元素
2014/01/09 Javascript
对jquery的ajax进行二次封装以及ajax缓存代理组件:AjaxCache详解
2016/04/11 Javascript
学习 NodeJS 第八天:Socket 通讯实例
2016/12/21 NodeJs
JSONP基础知识详解
2017/03/19 Javascript
基于layer.js实现收货地址弹框选择然后返回相应的地址信息
2017/05/26 Javascript
jsonp跨域请求详解
2017/07/13 Javascript
对vuex中store和$store的区别说明
2020/07/24 Javascript
[11:57]《一刀刀一天》第十七期:TI中国军团加油!
2014/05/26 DOTA
简析Python的闭包和装饰器
2016/02/26 Python
Python 基础知识之字符串处理
2017/01/06 Python
在python中实现对list求和及求积
2018/11/14 Python
Python获取数据库数据并保存在excel表格中的方法
2019/06/12 Python
简单了解django orm中介模型
2019/07/30 Python
python 的 openpyxl模块 读取 Excel文件的方法
2019/09/09 Python
python collections模块的使用
2020/10/16 Python
x-ua-compatible content=”IE=7, IE=9″意思理解
2013/07/22 HTML / CSS
5分钟实现Canvas鼠标跟随动画背景
2019/11/18 HTML / CSS
New Balance波兰官方商城:始于1906年,百年慢跑品牌
2017/08/15 全球购物
Java TransactionAPI (JTA) 主要包含几部分
2012/12/07 面试题
中班开学寄语
2014/04/04 职场文书
演讲稿格式
2014/04/30 职场文书
社团活动总结怎么写
2014/06/30 职场文书
世界遗产导游词
2015/02/13 职场文书
地球一小时活动总结
2015/02/27 职场文书
项目经理岗位职责范本
2015/04/01 职场文书
2016高考寄语或鼓励的话语
2015/12/04 职场文书
护理自荐信
2019/05/14 职场文书
vue引入Excel表格插件的方法
2021/04/28 Vue.js
python游戏开发Pygame框架
2022/04/22 Python