JavaScript中常见继承方式
JavaScript作为弱类型语言,继承也是其强大的特性之一,那么如何在JavaScript中实现继承呢?
1,原型链继承
下面是最简单的原型链继承写法,代码如下:
Father.prototype={ getName:function(){ return '我的名字是:'+this.name; } }; function Father(name){ this.likeColor=['red']; } function Son(name){ this.name=name; } Son.prototype=new Father(); var son1=new Son(); son1.likeColor.push('green'); console.log(son1.likeColor);// ["red", "green"] var son2=new Son(); console.log(son2.likeColor);// ["red","green"]
优点:
1,父类对象中的属性和方法子类实例都可以继承
2,实现简单
缺点:
1,包含引用类型值的原型属性会被所有实例共享,一个实例改变了该属性,其它实例也会受到影响。
2,子类实例化时不能向父类构造函数传递参数。
2,借用构造函数
上面出现的两个问题可以通过借用构造函数的方式解决,如下实例:
function Father(name){ this.likeColor=['red']; this.name=name; this.getName=function(){ return '我的名字是:'+this.name; } } function Son(name){ Father.call(this,name); } var son1=new Son('张三峰'); son1.likeColor.push('green'); console.log(son1.likeColor);// ["red", "green"] console.log(son1.getName());//我的名字是:张三峰 var son2=new Son('张无忌'); console.log(son2.likeColor);// ["red"] console.log(son2.getName());//我的名字是:张无忌
使用借用构造函数的方式确实把上面两个问题都得到了解决,如果仅仅使用借用构造函数那么就无法避免构造函数模式存在的问题-----方法和属性都在构造函数中定义,父类原型中定义的属性和方法对子类不可见,复用就无从谈起。
优点:
1,不存在父类中引用类型属性共享的问题
2,构建子类型实例时可以向父类构造函数传递参数
缺点:
1,子类实例无法继承父类原型中的属性和方法。
2,要继承的属性和方法都要写在构造函数中,导致每实例化一次子类对象都要重新执行一次这些属性和方法,这样缺少了代码复用,影响代码性能。
3,组合继承
组合继承可以解决单独使用原型链继承和单独使用借用构造函数继承存在的问题,如下实例:
Father.prototype={ getName:function(){ return '我的名字是:'+this.name; } }; function Father(name){ this.likeColor=['red']; this.name=name; } function Son(firstName){ Father.call(this,firstName); } Son.prototype=new Father(); var son1=new Son('张三峰'); son1.likeColor.push('green'); console.log(son1.likeColor);// ["red", "green"] console.log(son1.getName());//我的名字是:张三峰 var son2=new Son('张无忌'); console.log(son2.likeColor);// ["red"] console.log(son2.getName());//我的名字是:无忌
组合继承避免了原型链和借用构造函数的缺点,融合二者的优点,成为最佳实现继承方式,最大的缺点就是父类构造函数会执行两次,子类原型对象会继承父类实例的全部属性,所以不得不在调用子类构造函数时在子类实例对象中重写这些属性。
4,寄生组合继承(圣杯模式)
寄生组合继承模式可以解决组合继承中存在的问题,如下实例:
var inherit=(function(){ return function(Target,Origin){ var prototype=Object.create(Origin.prototype) prototype.constructor=Target; Target.prototype=prototype; } })(); Father.prototype={ getName:function(){ return '我的名字是:'+this.name; } }; function Father(name){ this.likeColor=['red']; this.name=name; } function Son(name){ Father.call(this,name); } inherit(Son,Father); var son1=new Son('张三峰'); son1.likeColor.push('green'); console.log(son1.likeColor);// ["red", "green"] console.log(son1.getName());//我的名字是:张三峰 var son2=new Son('张无忌'); console.log(son2.likeColor);// ["red"] console.log(son2.getName());//我的名字是:张无忌
优点:几乎完美
缺点:实现较为复杂