浅谈js中的三种继承方式及其优缺点


Posted in Javascript onAugust 10, 2016

第一种,prototype的方式:

//父类 
function person(){ 
  this.hair = 'black'; 
  this.eye = 'black'; 
  this.skin = 'yellow'; 
  this.view = function(){ 
    return this.hair + ',' + this.eye + ',' + this.skin; 
  } 
} 

//子类 
function man(){ 
  this.feature = ['beard','strong']; 
} 

man.prototype = new person(); 
var one = new man(); 

console.log(one.feature); //['beard','strong'] 
console.log(one.hair); //black 
console.log(one.eye); //black 
console.log(one.skin); //yellow 
console.log(one.view()); //black,black,yellow

这种方式最为简单,只需要让子类的prototype属性值赋值为被继承的一个实例就行了,之后就可以直接使用被继承类的方法了。

prototype 属性是啥意思呢? prototype 即为原型,每一个对象 ( 由 function 定义出来 ) 都有一个默认的原型属性,该属性是个对象类型。

并且该默认属性用来实现链的向上攀查。意思就是说,如果某个对象的属性不存在,那么将通过prototype属性所属对象来查找这个属性。如果 prototype 查找不到呢?

js会自动地找prototype的prototype属性所属对象来查找,这样就通过prototype一直往上索引攀查,直到查找到了该属性或者prototype最后为空 (“undefined”);

例如上例中的one.view()方法,js会先在one实例中查找是否有view()方法,因为没有,所以查找man.prototype属性,而prototype的值为person的一个实例,

该实例有view()方法,于是调用成功。

第二种,apply的方式:

//父类 
function person(){ 
  this.hair = 'black'; 
  this.eye = 'black'; 
  this.skin = 'yellow'; 
  this.view = function(){ 
    return this.hair + ',' + this.eye + ',' + this.skin; 
  } 
} 

//子类 
function man(){ 
  // person.apply(this,new Array()); 
  person.apply(this,[]); 
  this.feature = ['beard','strong']; 
} 

var one = new man(); 

console.log(one.feature); //['beard','strong'] 
console.log(one.hair); //black 
console.log(one.eye); //black 
console.log(one.skin); //yellow 
console.log(one.view()); //black,black,yellow

注意:如果apply参数为空,即没有参数传递,则通过 new Array() 、[] 来传递,null 无效。

第三种,call+prototype的方式:

//父类 
function person(){ 
  this.hair = 'black'; 
  this.eye = 'black'; 
  this.skin = 'yellow'; 
  this.view = function(){ 
    return this.hair + ',' + this.eye + ',' + this.skin; 
  } 
} 

//子类 
function man(){ 
  // person.apply(this,new Array()); 
  person.call(this,[]); 
  this.feature = ['beard','strong']; 
} 

man.prototype = new person(); 
var one = new man(); 

console.log(one.feature); //['beard','strong'] 
console.log(one.hair); //black 
console.log(one.eye); //black 
console.log(one.skin); //yellow 
console.log(one.view()); //black,black,yellow

call方式的实现机制却要多一条 man.prototype = new person(); 为啥呢?
那是因为call方法只实现了方法的替换而没有作对象属性的复制操作。
google Map API 的继承就是使用这种方式。

上面总结了三种继承方式的实现。但是每种方法都有其优缺点。

假如父类是这样的:

//父类 
function person(hair,eye,skin){ 
  this.hair = hair; 
  this.eye = eye; 
  this.skin = skin; 
  this.view = function(){ 
    return this.hair + ',' + this.eye + ',' + this.skin; 
  } 
}

子类应该如何设计,使子类man在创建对象的同时传递参数到父类person,prototype的继承方式就不适用了,
必须采用apply或者call的方式了:

//apply方式 
//子类 
function man(hair,eye,skin){ 
  person.apply(this,[hair,eye,skin]); 
  this.feature = ['beard','strong']; 
} 
//call方式 
//子类 
function man(hair,eye,skin){ 
  person.call(this,hair,eye,skin); 
  this.feature = ['beard','strong']; 
}

但是用apply方法也还是有缺点的,为什么?在js中,我们有个非常重要的运算符就是”instanceof”,该运算符用来比较某个对向是否为某种类型。

对于这个例子,one实例除了是man类型,也应该是person类型,但是apply方式继承之后,one却不属于person类型,即(one instanceof person)的值为false。

经此种种,最好的继承方式就是call+prototype方式了,之后你可以试一下(one instanceof BaseClass)的值是否为true。

第三种继承方式也有缺陷:子类new对象时要传一遍父类所需的参数,而且会重现父类中的属性和方法,下面这种继承方式才是完善的:

function Person(name){   
  this.name = name; 
} 

Person.prototype.getName = function() { 
  return this.name; 
} 

function Chinese(name, nation) { 
  Person.call(this, name); 
  this.nation = nation; 
} 

//继承方法 
function inherit(subClass, superClass) { 
  function F() {} 
  F.prototype = superClass.prototype; 
  subClass.prototype = new F(); 
  subClass.prototype.constructor = subClass.constructor; 
} 

inherit(Chinese, Person); 

Chinese.prototype.getNation = function() { 
  return this.nation; 
}; 

var p = new Person('shijun'); 
var c = new Chinese("liyatang", "China"); 

console.log(p); // Person {name: "shijun", getName: function} 
console.log(c); // Chinese {name: "liyatang", nation: "China", constructor: function, getNation: function, getName: function} 


console.log(p.constructor); // function Person(name){} 
console.log(c.constructor); // function Chinese(){} 

console.log(c instanceof Chinese); // true 
console.log(c instanceof Person); // true

以上这篇浅谈js中的三种继承方式及其优缺点就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery旋转插件—rotate支持(ie/Firefox/SafariOpera/Chrome)
Jan 16 Javascript
动态获取复选框checkbox选中个数的jquery代码
Jun 25 Javascript
javascript实现动态模态绑定grid过程代码
Sep 22 Javascript
基于jQuery实现select下拉选择可输入附源码下载
Feb 03 Javascript
jQuery插件passwordStrength密码强度指标详解
Jun 24 Javascript
JS实现HTML标签转义及反转义
Apr 14 Javascript
将鼠标焦点定位到文本框最后(代码分享)
Jan 11 Javascript
Angular.js中控制器之间的传值详解
Apr 24 Javascript
JavaScript比较两个数组的内容是否相同(推荐)
May 02 Javascript
BootStrap selectpicker后台动态绑定数据的方法
Jul 28 Javascript
vue侧边栏动态生成下级菜单的方法
Sep 07 Javascript
使用JS判断页面是首次被加载还是刷新
May 26 Javascript
jQuery+HTML5+CSS3制作支持响应式布局时间轴插件
Aug 10 #Javascript
基于js中的原型、继承的一些想法
Aug 10 #Javascript
新入门node.js必须要知道的概念(必看篇)
Aug 10 #Javascript
jQuery制作圣诞主题页面 更像是爱情影集
Aug 10 #Javascript
jquery实现拖动效果
Aug 10 #Javascript
JS弹出新窗口被拦截的解决方法
Aug 09 #Javascript
只要1K 纯JS脚本送你一朵3D红色玫瑰
Aug 09 #Javascript
You might like
php修改NetBeans默认字体的大小
2013/07/02 PHP
php获取当前时间的毫秒数的方法
2014/01/26 PHP
php实现只保留mysql中最新1000条记录
2015/06/18 PHP
PHP正则匹配日期和时间(时间戳转换)的实例代码
2016/12/14 PHP
jquery简单体验
2007/01/10 Javascript
Javascript 面向对象(二)封装代码
2012/05/23 Javascript
jQuery选择器中含有空格的使用示例及注意事项
2013/08/25 Javascript
常用的jQuery前端技巧收集
2014/12/24 Javascript
jQuery多条件筛选如何实现
2015/11/04 Javascript
Node.js中路径处理模块path详解
2016/11/14 Javascript
jQuery简单获取DIV和A标签元素位置的方法
2017/02/07 Javascript
jquery mobile实现可折叠的导航按钮
2017/03/11 Javascript
基于JavaScript实现类名的添加与移除
2017/04/23 Javascript
详解VueJS 数据驱动和依赖追踪分析
2017/07/26 Javascript
vue+Java后端进行调试时解决跨域问题的方式
2017/10/19 Javascript
React native ListView 增加顶部下拉刷新和底下点击刷新示例
2018/04/27 Javascript
layui 设置table 行的高度方法
2018/08/17 Javascript
JointJS JavaScript流程图绘制框架解析
2019/08/15 Javascript
原生js实现无缝轮播图
2020/01/11 Javascript
vue-cli设置css不生效的解决方法
2020/02/07 Javascript
详解ES6数组方法find()、findIndex()的总结
2020/05/12 Javascript
vue的hash值原理也是table切换实例代码
2020/12/14 Vue.js
[49:05]OG vs Newbee 2019DOTA2国际邀请赛淘汰赛 胜者组 BO3 第二场 8.21.mp4
2020/07/19 DOTA
使用cx_freeze把python打包exe示例
2014/01/24 Python
在centos7中分布式部署pyspider
2017/05/03 Python
Diango + uwsgi + nginx项目部署的全过程(可外网访问)
2018/04/22 Python
解决python Markdown模块乱码的问题
2019/02/14 Python
实例详解python函数的对象、函数嵌套、名称空间和作用域
2019/05/31 Python
学点简单的Django之第一个Django程序的实现
2021/02/24 Python
What's the difference between deep copy and shallow copy? (深拷贝与浅拷贝有什么区别)
2015/11/10 面试题
工商管理系学生的自我评价分享
2013/11/29 职场文书
工作作风整顿个人剖析材料
2014/10/11 职场文书
市贸粮局召开党的群众路线教育实践活动总结大会新闻稿
2014/10/21 职场文书
煤矿安全保证书
2015/02/27 职场文书
学雷锋活动简报
2015/07/20 职场文书
感恩教育主题班会
2015/08/12 职场文书