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 相关文章推荐
js data日期初始化的5种方法
Dec 29 Javascript
jquery实现更改表格行顺序示例
Apr 30 Javascript
推荐 21 款优秀的高性能 Node.js 开发框架
Aug 18 Javascript
12306验证码破解思路分享
Mar 25 Javascript
javascript实现鼠标拖动改变层大小的方法
Apr 30 Javascript
JS中生成随机数的用法及相关函数
Jan 09 Javascript
JavaScript小技巧整理篇(非常全)
Jan 26 Javascript
详解AngularJS中$filter过滤器使用(自定义过滤器)
Feb 04 Javascript
jQuery实现文章图片弹出放大效果
Apr 06 jQuery
Vue自定义多选组件使用详解
Sep 08 Javascript
vue-amap根据地址回显地图并mark的操作
Nov 03 Javascript
正则表达式基础与常用验证表达式
Jun 16 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
DOTA2 无惧惊涛骇浪 昆卡大型水友攻略
2020/04/20 DOTA
php设计模式 Factory(工厂模式)
2011/06/26 PHP
使用php 获取时间今天明天昨天时间戳的详解
2013/06/20 PHP
YII框架关联查询操作示例
2019/04/29 PHP
javascript下给元素添加事件的方法与代码
2007/08/13 Javascript
用js实现层随着内容大小动态渐变改变 推荐
2009/12/19 Javascript
javascript 图片上一张下一张链接效果代码
2010/03/12 Javascript
js 判断计算字符串长度/判断空的简单方法
2013/08/05 Javascript
纯javascript实现图片延时加载方法
2015/08/21 Javascript
JavaScript面试开发常用的知识点总结
2016/08/08 Javascript
jQuery如何解决IE输入框不能输入的问题
2016/10/08 Javascript
JS 循环li添加点击事件 (闭包的应用)
2016/12/10 Javascript
Javascript 实现全屏滚动实例代码
2016/12/31 Javascript
微信小程序 聊天室简单实现
2017/04/19 Javascript
JavaScript实现form表单的多文件上传
2020/03/27 Javascript
如何将HTML字符转换为DOM节点并动态添加到文档中详解
2018/08/19 Javascript
Python3搜索及替换文件中文本的方法
2015/05/22 Python
Python爬虫利用cookie实现模拟登陆实例详解
2017/01/12 Python
python3利用ctypes传入一个字符串类型的列表方法
2019/02/12 Python
python+opencv实现摄像头调用的方法
2019/06/22 Python
python顺序执行多个py文件的方法
2019/06/29 Python
python如何爬取动态网站
2020/09/09 Python
Python实现七个基本算法的实例代码
2020/10/08 Python
HTML5 预加载让页面得以快速呈现
2013/08/13 HTML / CSS
德国家用电器购物网站:Premiumshop24
2019/08/22 全球购物
如何防止同一个帐户被多人同时登录
2013/08/01 面试题
家长对老师的评语
2014/04/18 职场文书
省级青年文明号申报材料
2014/05/23 职场文书
2014年客户经理工作总结
2014/11/20 职场文书
办公室岗位职责范本
2015/04/11 职场文书
公积金具结保证书
2015/05/11 职场文书
小英雄雨来观后感
2015/06/09 职场文书
安全教育日主题班会
2015/08/13 职场文书
七年级话题作文之执着
2019/11/19 职场文书
Redis 配置文件重要属性的具体使用
2021/05/20 Redis
苹果的回收机器人可以通过拆解iPhone获取大量的金和铜并外公布了环境保护最新进展
2022/04/21 数码科技