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

 更新时间:2016年08月10日 09:22:42   投稿:jingxian  
下面小编就为大家带来一篇浅谈js中的三种继承方式及其优缺点。小编觉得挺不错的,现在就分享给大家,也给大家做个参考,一起跟随小编过来看看吧

第一种,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实现点击单选按钮改变输入框中文本域内容的方法

    JavaScript实现点击单选按钮改变输入框中文本域内容的方法

    这篇文章主要介绍了JavaScript实现点击单选按钮改变输入框中文本域内容的方法,涉及javascript单选按钮控制页面元素样式的相关技巧,非常简单实用,需要的朋友可以参考下
    2015-08-08
  • Javascript实现简易导航栏

    Javascript实现简易导航栏

    这篇文章主要为大家详细介绍了Javascript实现简易导航栏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • 前端的框架TDesign小程序组件库体验

    前端的框架TDesign小程序组件库体验

    TDesign是腾讯各业务团队在服务业务过程中沉淀的一套企业级设计体系,下面这篇文章主要给大家介绍了关于前端的框架TDesign小程序组件库体验的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2022-11-11
  • javascript的currying函数介绍

    javascript的currying函数介绍

    curring的概念将函数式编程的概念和默认参数以及可变参数结合在一起.一个带n个参数,curried的函数固化第一个参数为固定参数,并返回另一个带n-1个参数的函数对象,分别类似于LISP的原始函数car和cdr的行为。currying能泛化为偏函数应用(partial function application, PFA),p 这种函数将任意数量(顺序)的参数的函数转化为另一个带剩余参数的函数对象
    2012-02-02
  • 如何防止INPUT按回车自动提交表单FORM

    如何防止INPUT按回车自动提交表单FORM

    为了防止INPUT按回车form自动提交,可以以下两种方法:增加一个隐藏的input。为input增加一个按键事件来阻止form提交。具体详情可以参考下本文
    2016-12-12
  • JSON字符串转JSON对象

    JSON字符串转JSON对象

    本文给大家分享的是如何使用javascript实现JSON字符串转JSON对象的方法,这里记录下来,有需要的小伙伴可以参考下。
    2015-07-07
  • Bootstrap编写导航栏和登陆框

    Bootstrap编写导航栏和登陆框

    这篇文章主要为大家详细介绍了Bootstrap导航栏和登陆框的编写代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-05-05
  • C++中的string类的用法小结

    C++中的string类的用法小结

    通过在网站上的资料搜集,得到了很多关于string类用法的文档,通过对这些资料的整理和加入一些自己的代码,就得出了一份比较完整的关于string类函数有哪些和怎样用的文档了!
    2015-08-08
  • 微信小程序 网络通信实现详解

    微信小程序 网络通信实现详解

    这篇文章主要介绍了微信小程序 网络通信实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07
  • Javascript在IE下设置innerHTML时出现未知的运行时错误的解决方法

    Javascript在IE下设置innerHTML时出现未知的运行时错误的解决方法

    程序代码思路大致如下,想动态的改变tr标签的innerHTML内容,但是IE却报未知的运行时错误
    2011-01-01

最新评论