继承是面向对象开发的不可或缺的特点,javascript没有像java类似的类,主要应用的是原型对象来实现继承,学习总结了如下几种继承模式。
一、 原型链继承
上节知道每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,实例都包含一个指向原型的内部指针。那么让一个原型对象等于另一个类型的实例,此时的原型对象就包含了一个指向另一个原型的指针,而另一个原型对象又包含着一个指向另一个的构造函数指针,这样层层递进,就构成了实例与原型的链条,实现了继承。
function Animal(){
this.type="animal";
}
Animal.prototype.getType=function(){
return this.type;
}
function Dog(){
this.name="dog";
}
Dog.prototype=new Animal();
Dog.prototype.getName=function(){
return this.name;
}
var dog=new Dog();
alert(dog.getType()) //animal
从例子可知dog实例继承了Animal的原型方法和属性。同时也有它的缺点就是因为共享性,父构造函数中若有引用属性,不同的实例的修改都将会是共享的,第二个问题就是创建子类型的实例不能像父构造函数传递参数。
原型链注意点:1、子类型原型添加方法的代码一定要放在替换原型的语句之后,像上面例子一样;2、子类型原型添加方法时不能用原型字面量,因为这样会重写原型对象,切断了和父类型构造函数联系,失去了继承。
二、 组合继承
将原型链和构造函数组合在一起,发挥二者之长的一种继承模式,使用原型链实现对原型属性和方法的继承,借用构造函数实现对实例属性的继承。
function Animal(type){
this.type=type;
this.all=["rabbit","chicken","cow"];
}
Animal.prototype.getType=function(){
alert(this.type);
}
function Dog(type,name){
Animal.call(this,type);
this.name=name;
}
Dog.prototype=new Animal();
Dog.prototype.constructor=Dog;
Dog.prototype.getName=function(){
alert(this.name);
}
var dog=new Dog("dog","小白");
dog.all.push("dog");
alert(dog.all); //rabbit,chicken,cow,dog
dog.getType(); //dog
dog.getName(); //小白
var dog2=new Dog("dog特种","小黑");
dog2.all.push("dog特种");
alert(dog2.all); //rabbit,chicken,cow,dog特种
dog2.getType(); //dog特种
dog2.getName(); //小黑
这样能通过子类型里的构造函数调用父类型的构造函数,向父类型里传递参数,这样也保证了子类型创造的实例拥有自己的属性,也拥有原型对象里共同的方法。但是这有一个问题就是在子构造函数里调用父构造函数实现了属性的继承,然后又将子类型的原型指向父类型的实例,这样造成了属性的重复,只是实例里的属性覆盖了原型里的属性,所以才没有被调用。
三、 原型式继承
道格拉斯提出的借助原型可以基于已有的对象创建新对象,同时不必创建自定义类型。
function object(o){
function F(){}
F.prototype=o;
return new F();
}
传入一个对象,返回出一个把传入对象当原型对象的实例。调用该函数时,返回的对象就继承了传入对象的所有方法和属性。
var animal={
type:"animal",
all:['rabbit','cow','cat'],
}
var dog=object(animal);
dog.name="dogg";
dog.all.push('dog');
alert(dog.type);
alert(dog.all);
es5新增的objetc.create()方法规范化了原型继承,传入2个参数,一个新对象原型的对象,另一个是新对象定义的额外属性的对象
*四、寄生组合式继承*
在组合继承里出现的属性重复问题,解决这个问题出现了寄生组合继承,借用构造函数继承属性,通过原型链形式继承方法,将组合继承里的Dog.prototype=new Animal();改成只是继承父类型的原型对象即只拷贝父类型的原型对象。
inheritPrototype(animal,dog);
function inheritPrototype(animal,dog){
var prototype=Object(animal.prototype);
prototype.constructor=dog;
dog.prototype=prototype;
}
还有另外一种没有利用构造函数的继承就是拷贝,把新对象拷贝到目标对象里去,返回新的对象,实现继承
var Doctor={
say:function(){
alert("吃饭去");
}
};
var Copy=function (p) {
var c = {};
c=this;
for (var i in p) {
c[i] = p[i];
}
c.uber = p;
return c;
}
Doctor.extend=Copy;
Doctor.extend({
test:function(){
alert("马上去吃饭");
}
})
Doctor.say(); //吃饭去
Doctor.test(); //马上去吃饭
Doctor可以通过extend可以继承任何传进的对象的属性和方法。Jquery的 .extend(object)和 .fn.extend就是这样实现的继承达到制作新的插件