史上最为详细的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实现仿Windows关机效果
Mar 10 Javascript
使用jQuery实现星级评分代码分享
Dec 09 Javascript
javascript html5摇一摇功能的实现
Apr 19 Javascript
jquery实现的回旋滚动效果完整实例【附demo源码下载】
Sep 20 Javascript
KnockoutJS 3.X API 第四章之数据控制流if绑定和ifnot绑定
Oct 10 Javascript
微信小程序左滑删除效果的实现代码
Feb 20 Javascript
Bootstrap实现的经典栅格布局效果实例【附demo源码】
Mar 30 Javascript
Vue添加请求拦截器及vue-resource 拦截器使用
Nov 23 Javascript
Vue组件之单向数据流的解决方法
Nov 10 Javascript
JavaScript格式化json和xml的方法示例
Jan 22 Javascript
JavaScript实现简单日历效果
Sep 11 Javascript
微信小程序实现轮播图指示器
Jun 25 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
玩转图像函数库―常见图形操作
2006/09/03 PHP
在VS2008中编译MYSQL5.1.48的方法
2010/07/03 PHP
部署PHP项目应该注意的几点事项分享
2013/12/20 PHP
PHP使用xmllint命令处理xml与html的方法
2014/12/15 PHP
PHP中error_reporting()用法详解
2015/08/31 PHP
php实现简单的MVC框架实例
2015/09/23 PHP
仿163填写邮件地址自动显示下拉(无优化)
2008/11/05 Javascript
基于jquery的cookie的用法
2011/01/10 Javascript
jquery插件开发注意事项小结
2013/06/04 Javascript
Extjs4 Treegrid 使用心得分享(经验篇)
2013/07/01 Javascript
JS+flash实现chrome和ie浏览器下同时可以复制粘贴
2013/09/22 Javascript
老生常谈onBlur事件与onfocus事件(js)
2016/07/09 Javascript
JavaScript简单拖拽效果(1)
2017/05/17 Javascript
Vue使用vue-cli创建项目
2017/09/01 Javascript
微信小程序实现YDUI的ScrollTab组件
2018/02/02 Javascript
Django+vue跨域问题解决的详细步骤
2019/01/20 Javascript
VueCli4项目配置反向代理proxy的方法步骤
2020/05/17 Javascript
jquery实现简单每周轮换的日历
2020/09/10 jQuery
基于element-ui对话框el-dialog初始化的校验问题解决
2020/09/11 Javascript
python字典的常用操作方法小结
2016/05/16 Python
Python存取XML的常见方法实例分析
2017/03/21 Python
PyQt 线程类 QThread使用详解
2017/07/16 Python
Python使用psutil获取进程信息的例子
2019/12/17 Python
Django模型中字段属性choice使用说明
2020/03/30 Python
使用CSS3制作一个简单的进度条(demo)
2017/05/23 HTML / CSS
Uber Eats台湾:寻找附近提供送餐服务的餐厅
2018/05/07 全球购物
HQhair美国/加拿大:英国化妆品、美容及美发产品商城
2019/04/15 全球购物
怎么写好自荐书
2014/03/02 职场文书
四年级学生评语大全
2014/04/21 职场文书
学术研讨会主持词
2015/07/04 职场文书
2019入党申请书格式和范文
2019/06/25 职场文书
Mysql中存储引擎的区别及比较
2021/06/04 MySQL
Oracle创建只读账号的详细步骤
2021/06/07 Oracle
基于Python实现一个春节倒计时脚本
2022/01/22 Python
分享提高 Python 代码的可读性的技巧
2022/03/03 Python
vue使用refs获取嵌套组件中的值过程
2022/03/31 Vue.js