在上篇《js 原型(prototype)继承相关》中,最后提到了关于函数的定义和继承,本篇幅给出其实现,这种方式书中称为 组合继承,看代码:
function SuperType(name){
this.name = name;
this.colors = ["red","blue","green"];
}
//在SuperType的原型中定义方法
SuperType.prototype.sayName = function(){
alert(this.name);
}
function SubType(name,age){
SuperType.call(this,name);
this.age = age;//SubType的新属性
}
SubType.prototype = new SuperType();
***SubType.prototype.constructor = SubType;***
SubType.prototype.sayAge = function(){
alert(this.age);
}
var instance1 = new SubType("xiaolu",23);
instance1.colors.push("black");
alert(instance1.colors); //red,blue,green,black
instance1.sayName();//xiaolu
instance1.sayAge();//23
var instance2 = new SubType("xiaowang",23);
alert(instance2.colors);//red,blue,green
instance2.sayName();//xiaowang
instance2.sayAge();//23
嗯,如你所见【结果是我们想要的】,而为什么要提出这种组合继承呢?最大的好处是首先避免了直接原型链实现继承那种将对象中实例属性变成了原型中的属性【也就成为了共享的了】从而导致一个对象对属性的修改,影响到其他对象中的属性【可以见上篇】,同时,没有在构造函数中对方法进行定义,避免了每个对象都对方法进行一次定义【浪费空间,也不优雅】。但是,等等,有疑问了:
SubType.prototype = new SuperType();
代码中还是有这一句啊,这样不是把SuperType中的实体属性变成了SubType的原型了吗?原型中的属性是共享的吖?为什么instance1的push操作,没有影响到instance2的colors属性呢?
发现这个问题,嗯,首先你是个爱思考的人- -
其实吧,你,说的也对。原型中的属性是共享的,这一句代码的存在也确实如你所说,把实体属性变成了原型中的属性。这个没有错。但是注意这一句:
function SubType(name,age){
SuperType.call(this,name); //////////注意咯
this.age = age;//SubType的新属性
}
发现没有?在SubType中首先调用了SuperType构造函数,再想想上篇文章,应该理解了,嗯,这里呢,给new出来的SubType对象中,又重新塞入了name和colors属性【存在于SuperType中的属性】。这样子的话,SubType的prototype对象中确实也是有name和Colors了,但是,SubType实体中也是有这些属性的,而我们知道,对于属性(或者方法)的获取,是先从实体中找,找不到的情况下,去原型中找,然后再往上。那么实体中有了,自然就不需要去原型中找了。【有点绕,不太理解的话,可以细细思考下】,当然了,也可以说这是这个模式的一个缺点。那么可不可以不要:
SubType.prototype = new SuperType();
这句话,因为它的存在,导致了原型中还有一份SuperType的属性。哦,你想的很对,但是,不要还真不行!
因为什么呢?你自己先想想- -
你需要SuperType的实例【本例子中没有】或者SuperType原型中定义的函数方法【比如 sayName】,如果去掉了这一句,继承链断了,那么
instance1.sayName();//xiaolu
就会出错【sayName是什么???】
***SubType.prototype.constructor = SubType;***
个人觉得,在本例中,这一句话可以不要的。当然了,存在的意义也许是你可以使用instanceof操作符判断对象类型了吧【- -】