6种JavaScript继承方式及优缺点(小结)


Posted in Javascript onFebruary 06, 2020

温馨提示:想要更好的理解JS继承方式,须了解构造函数、原型对象、实例化对象、原型链等概念

第一种:原型链继承

利用原型链的特点进行继承

function Parent(){
  this.name = 'web前端';
  this.type = ['JS','HTML','CSS'];
}
Parent.prototype.Say=function(){
  console.log(this.name);
}
function Son(){};
Son.prototype = new Parent();
son1 = new Son();
son1.Say();

以上例子解释:

①创建一个叫做Parent的构造函数,暂且称为父构造函数,里面有两个属性name、type
②通过Parent构造函数的属性(即原型对象)设置Say方法,此时,Parent有2个属性和1个方法
③创建一个叫做Son的构造函数,暂且称为子构造函数
④设置Son的属性(即原型对象)值为父构造函数Parent的实例对象,即子构造函数Son继承了父构造函数Parent,此时Son也有2个属性和1个方法
⑤对Son构造函数进行实例化,结果赋值给变量son1,即son1为实例化对象,同样拥有2个属性和1个方法
⑥输出son1的Say方法,结果为"web前端"

优点:可以实现继承

缺点:
①因为Son.prototype(即原型对象)继承了Parent实例化对象,这就导致了所有Son实例化对象都一样,都共享有原型对象的属性及方法。代码如下:

son1 = new Son();
son2 = new Son();
son1.type.push('VUE');
console.log(son1.type);//['JS','HTML','CSS','VUE']
console.log(son2.type);//['JS','HTML','CSS','VUE']

结果son1、son2都是['JS','HTML','CSS','VUE']
②Son构造函数实例化对象无法进行参数的传递

第二种:构造函数继承

通过构造函数call方法进行继承,直接来看代码:

function Parent(){
  this.name = 'web前端';
  this.type = ['JS','HTML','CSS'];
}
function Son(){
  Parent.call(this);
}
son1 = new Son();
son1.type.push('VUE');
console.log(son1.type);//['JS','HTML','CSS','VUE']
son2 = new Son();
console.log(son2.type);//['JS','HTML','CSS']

以上例子解释:
①创建父级构造函数Parent,有name、type两个属性
②创建子级构造函数Son,函数内部通过call方法调用父级构造函数Parent,实现继承
③分别创建构造函数Son的两个实例化对象son1、son2,对son1的type属性新增元素,son2没有新增,结果不一样,说明实现了独立

优点:
①实现实例化对象的独立性;
②还可以给实例化对象添加参数

function Parent(name){
  this.name = name;
}
function Son(name){
  Parent.call(this,name);
}
son1 = new Son('JS');
console.log(son1);//JS
son2 = new Son('HTML');
console.log(son2);//HTML

缺点:
①方法都在构造函数中定义,每次实例化对象都得创建一遍方法,基本无法实现函数复用
②call方法仅仅调用了父级构造函数的属性及方法,没有办法调用父级构造函数原型对象的方法

第三种:组合继承

利用原型链继承和构造函数继承的各自优势进行组合使用,还是看代码:

function Parent(name){
  this.name = name;
  this.type = ['JS','HTML','CSS'];
}
Parent.prototype.Say=function(){
  console.log(this.name);
}
function Son(name){
  Parent.call(this,name);
}
Son.prototype = new Parent();
son1 = new Son('张三');
son2 = new Son('李四');
son1.type.push('VUE');
son2.type.push('PHP');
console.log(son1.type);//['JS','HTML','CSS','VUE']
console.log(son2.type);//['JS','HTML','CSS','PHP']
son1.Say();//张三
son2.Say();//李四

以上例子解释:
①创建一个叫做Parent的构造函数,里面有两个属性name、type
②通过Parent构造函数的属性(即原型对象)设置Say方法,此时,Parent有2个属性和1个方法
③创建子级构造函数Son,函数内部通过call方法调用父级构造函数Parent,实现继承
④子构造函数Son继承了父构造函数Parent,此时Son也有2个属性和1个方法
⑤分别创建构造函数Son的两个实例化对象son1、son2,传不同参数、给type属性新增不同元素、调用原型对象Say方法

优点:
①利用原型链继承,实现原型对象方法的继承
②利用构造函数继承,实现属性的继承,而且可以参数
组合函数基本满足了JS的继承,比较常用

缺点:
无论什么情况下,都会调用两次父级构造函数:一次是在创建子级原型的时候,另一次是在子级构造函数内部

第四种:原型式继承

创建一个函数,将参数作为一个对象的原型对象

function fun(obj) {
  function Son(){};
  Son.prototype = obj;
  return new Son();
}    
var parent = {
  name:'张三'
}
var son1 = fun(parent);
var son2 = fun(parent);
console.log(son1.name);//张三
console.log(son2.name);//张三

以上例子解释:
①创建一个函数fun,内部定义一个构造函数Son
②将Son的原型对象设置为参数,参数是一个对象,完成继承
③将Son实例化后返回,即返回的是一个实例化对象
优缺点:跟原型链类似

第五种:寄生继承

在原型式继承的基础上,在函数内部丰富对象

function fun(obj) {
  function Son() { };
  Son.prototype = obj;
  return new Son();
}
function JiSheng(obj) {
  var clone = fun(obj);
  clone.Say = function () {
    console.log('我是新增的方法');
  }
  return clone;
}
var parent = {
  name: '张三'
}
var parent1 = JiSheng(parent);
var parent2 = JiSheng(parent);
console.log(parent2.Say==parent1.Say);// false

以上例子解释:
①再原型式继承的基础上,封装一个JiSheng函数
②将fun函数返回的对象进行增强,新增Say方法,最后返回
③调用JiSheng函数两次,分别赋值给变量parent1、parent2
④对比parent1、parent2,结果为false,实现独立
优缺点:跟构造函数继承类似,调用一次函数就得创建一遍方法,无法实现函数复用,效率较低

这里补充一个知识点,ES5有一个新的方法Object.create(),这个方法相当于封装了原型式继承。这个方法可以接收两个参数:第一个是新对象的原型对象(可选的),第二个是新对象新增属性,所以上面代码还可以这样:

function JiSheng(obj) {
  var clone = Object.create(obj);
  clone.Say = function () {
    console.log('我是新增的方法');
  }
  return clone;
}
var parent = {
  name: '张三'
}
var parent1 = JiSheng(parent);
var parent2 = JiSheng(parent);
console.log(parent2.Say==parent1.Say);// false

第六种:寄生组合继承

利用组合继承和寄生继承各自优势
组合继承方法我们已经说了,它的缺点是两次调用父级构造函数,一次是在创建子级原型的时候,另一次是在子级构造函数内部,那么我们只需要优化这个问题就行了,即减少一次调用父级构造函数,正好利用寄生继承的特性,继承父级构造函数的原型来创建子级原型。

function JiSheng(son,parent) {
  var clone = Object.create(parent.prototype);//创建对象
  son.prototype = clone;   //指定对象
  clone.constructor = son;   //增强对象
}
function Parent(name){
  this.name = name;
  this.type = ['JS','HTML','CSS'];
}
Parent.prototype.Say=function(){
  console.log(this.name);
}
function Son(name){
  Parent.call(this,name);
}
JiSheng(Son,Parent);
son1 = new Son('张三');
son2 = new Son('李四');
son1.type.push('VUE');
son2.type.push('PHP');
console.log(son1.type);//['JS','HTML','CSS','VUE']
console.log(son2.type);//['JS','HTML','CSS','PHP']
son1.Say();//张三
son2.Say();//李四

以上例子解释:
①封装一个函数JiSheng,两个参数,参数1为子级构造函数,参数2为父级构造函数
②利用Object.create(),将父级构造函数原型克隆为副本clone
③将该副本作为子级构造函数的原型
④给该副本添加constructor属性,因为③中修改原型导致副本失去默认的属性

优缺点:
组合继承优点、寄生继承的有点,目前JS继承中使用的都是这个继承方法

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery使用手册之一
Mar 24 Javascript
javascript入门·对象属性方法大总结
Oct 01 Javascript
有关js的变量作用域和this指针的讨论
Dec 16 Javascript
js Dialog 实践分享
Oct 22 Javascript
一个简单的弹性返回顶部JS代码实现介绍
Jun 09 Javascript
jQuery调取jSon数据并展示的方法
Jan 29 Javascript
深入浅出 jQuery中的事件机制
Aug 23 Javascript
JS判断是否在微信浏览器打开的简单实例(推荐)
Aug 24 Javascript
Vue.js实现一个todo-list的上移下移删除功能
Jun 26 Javascript
jQuery结合jQuery.cookie.js插件实现换肤功能示例
Oct 14 jQuery
vue请求本地自己编写的json文件的方法
Apr 25 Javascript
React列表栏及购物车组件使用详解
Jun 28 Javascript
使用node.JS中的url模块解析URL信息
Feb 06 #Javascript
Node.JS获取GET,POST数据之queryString模块使用方法详解
Feb 06 #Javascript
node.JS事件机制与events事件模块的使用方法详解
Feb 06 #Javascript
如何通过javaScript去除字符串两端的空白字符
Feb 06 #Javascript
ckeditor一键排版功能实现方法分析
Feb 06 #Javascript
JavaScript如何判断input数据类型
Feb 06 #Javascript
如何使用Jquery动态生成二级选项列表
Feb 06 #jQuery
You might like
PHP中使用TCPDF生成PDF文档实例
2014/07/01 PHP
PHP封装分页函数实现文本分页和数字分页
2014/10/23 PHP
php动态变量定义及使用
2015/06/10 PHP
PHP数组相加操作及与array_merge的区别浅析
2016/11/26 PHP
PHP 二级子目录(后台目录)设置二级域名
2017/03/02 PHP
2017年最新PHP经典面试题目汇总(上篇)
2017/03/17 PHP
PHP实现自动发送邮件功能代码(qq 邮箱)
2017/08/18 PHP
PHP __call()方法实现委托示例
2019/05/20 PHP
javascript学习笔记(十八) 获得页面中的元素代码
2012/06/20 Javascript
JavaScript var声明变量背后的原理示例解析
2013/10/12 Javascript
jquery插件tooltipv顶部淡入淡出效果使用示例
2013/12/05 Javascript
详解JavaScript数组和字符串中去除重复值的方法
2016/03/07 Javascript
详解vue2路由vue-router配置(懒加载)
2017/04/08 Javascript
jquery append与appendTo方法比较
2017/05/24 jQuery
快速解决bootstrap下拉菜单无法隐藏的问题
2018/08/10 Javascript
详解vue在项目中使用百度地图
2019/03/26 Javascript
vue路由 遍历生成复数router-link的例子
2019/10/30 Javascript
js函数柯里化的方法和作用实例分析
2020/04/11 Javascript
vue 修改 data 数据问题并实时显示操作
2020/09/07 Javascript
JS中队列和双端队列实现及应用详解
2020/09/29 Javascript
[33:39]DOTA2上海特级锦标赛C组小组赛#2 LGD VS Newbee第二局
2016/02/27 DOTA
Python HTML解析模块HTMLParser用法分析【爬虫工具】
2019/04/05 Python
python基于opencv 实现图像时钟
2021/01/04 Python
欧洲最大的美妆零售网站:Feelunique
2017/01/14 全球购物
动态密码技术
2012/10/18 面试题
文职个人求职信范文
2013/09/23 职场文书
上班早退检讨书
2014/01/09 职场文书
应届毕业生如何写求职信
2014/02/16 职场文书
公司会计主管岗位责任制
2014/03/01 职场文书
家长会学生演讲稿
2014/04/26 职场文书
网络营销策划方案
2014/06/04 职场文书
2014年减负工作总结
2014/12/10 职场文书
邀请书格式范文
2015/02/02 职场文书
求职自我评价怎么写
2015/03/09 职场文书
旅游项目合作意向书
2015/05/08 职场文书
员工考勤管理制度
2015/08/06 职场文书