解决原型链的引用类型值问题 --- 组合继承
首先声明一个概念:我们虽然可以通过实例访问保存在原型中的值,但却不能通过实例重写原型中的值。如果我们在实例中给一个属性赋值,而且该属性与原型中的一个属性同名,那我们就在实例中创建该属性,该属性会屏蔽原型中的那个属性。
但是,虽然不能重写原型中的值,如果原型中包含有引用类型(数组,对象)的值的话,我们可以通过引用来修改原型中的值。
function Cat(){ };
Cat.prototype.type="Animal"; Cat.prototype.friends=['kitty','cookie']; Cat.prototype.speak=function(){ console.log("喵"); } var cat1=new Cat(); var cat2=new Cat(); cat1.friends.push('apple'); console.log(cat2.friends);
console.log(cat1.type);
console.log(cat2.type); cat1.speak(); cat2.speak();
原型中有一个共享的数组属性friends,每一个继承它的实例都可以对它进行修改。显然,每只猫咪都有应该自己的friends,而且不应该决定其他猫咪该有什么friends。好吧,为了猫咪们能够和谐相处,我们做一点点的改进。
//最常用的创建自定义类型的方法
function Cat(){ this.friends=['kitty','cookie']; }; Cat.prototype.type="Animal"; Cat.prototype.speak=function(){ console.log("喵"); } var cat1=new Cat(); var cat2=new Cat(); cat1.friends.push('apple'); console.log(cat2.friends);
console.log(cat1.type);
console.log(cat2.type);
cat1.speak();
cat2.speak();
构造函数为每只猫咪创建自己的friends属性,也就是说,把需要共享的属性和方法放在prototype里,而实例自己独立的属性,则放在构造函数里。
在原型链中,由于实例是另一个实例的原型对象这样的关系,我们即使把独立属性放在构造函数里,这个属性最终还是会成为另一个实例的原型里的属性,上面的问题又重演了,怎么办。先举个原型链的例子
function Sub(){ }; function Super(){ this.friends=['Tom','Jack']; } Sub.prototype=new Father(); Super.prototype.species="human"; var instance1=new Sub(); var instance2=new Sub(); instance1.friends.push('danyan'); console.log(instance1.friends);//['Tom','Jack','danyan'] console.log(instance2.friends);//['Tom','Jack','danyan']
Super的独立属性被写在构造函数里了,它的实例都将拥有不同的friends属性,但是,他的实例成了Sub的原型,Sub的实例,又将共享friends属性,怎么破。
分析一下,我们的目的是要Sub继承Super,而且Super中引用类型的属性不被Sub的实例共享。我们能不能像解决猫咪的问题那样,把这个引用类型的应该被独立出来的属性,放在Sub的构造函数里,让Sub的实例们各自生成自己的这个属性。答案,yes
//最常用的继承模式
function Sub(){ Super.apply(this,arguments); }; function Super(){ this.friends=['Tom','Jack']; } Sub.prototype=new Father(); Super.prototype.species="human"; var instance1=new Sub(); var instance2=new Sub(); instance1.friends.push('danyan'); console.log(instance1.friends);//['Tom','Jack','danyan'] console.log(instance2.friends);//['Tom','Tack']
如此一来,在调用Sub生成实例时,运行了Super函数(super在这里被当成一个普通的函数),为实例生成了各自的friends属性,屏蔽了Sub的原型即Super的实例中的friends属性。这种方法被称为组合继承。组合了经典继承(像sub那样借用super)和原型链继承。
浙公网安备 33010602011771号