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());//我的名字是:无忌
优点:
1,不存在父类中引用类型属性共享问题
2,父类原型中的属性和方法可复用
3,构建子类实例时可传递参数
缺点:
实例化子类对象时执行了两次父类构造函数:一次是在创建子类原型对象的时候,另一次是在子类构造函数内部调用call或者apply方法的时候。这就导致子类型在原型对象创建的时候就已经继承父类型中的所有实例属性,但是不得不在调用子类构造函数时重写所有的实例属性,真是多此一举。
4,寄生组合继承(圣杯模式)
寄生组合继承模式可以解决组合继承模式中父类构造函数执行两次的问题,如下实例:
var inherit=(function(){ var F=function(){}; return function(Target,Origin){ F.prototype=Origin.prototype; Target.prototype=new F(); Target.prototype.constructor=Target; Target.prototype.uber=Origin.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());//我的名字是:张无忌
优点:几乎完美
缺点:实现较为复杂