本篇介绍重写原型对象的原理及对实例的影响;原型对象的问题
重写原型对象
请看下例:
function Person(){
}
var Edward = new Person();
Person.prototype.name = "Sheldon";
Person.Prototype.age = 29;
Person.prototype.job = "Physical Scientist";
Person.prototype.sayName = function(){
alert(this.name);
};
Edward.sayName (); //"Sheldon"(没有问题)
在上例中,每添加一个属性或方法就要输入一遍 Person.prototype ,为了简化,更常见的做法是用一个新的对象字面量来重写原型,如:
function Person(){
}
Person.prototype = {
name : "Sheldon",
age : 29,
job : "Physical Scientist",
sayName : function(){
alert(this.name);
}
};
在上例中, Person.prototype 实质上被设置成了一个新对象,这个新对象自动获得的新的 constructor 属性也不再指向 Person 函数。尽管 instanceof 操作符还能返回正确的结果,但通过 constructor 已无法正确确定对象类型了。
var Amy = new Person();
alert(Amy instanceof Object); //true
alert(Amy instanceof Person); //true
alert(Amy.constructor == Person); //false
alert(Amy.constructor == Object); //true
如果 constructor 值很重要,可以将它特意设置回适当的值,但这会导致它的 Enumerable 特性被设置为 true 。
function Person(){
}
Person.prototype = {
constructor : Person,
name : "Sheldon",
age : 29,
job : "Physical Scientist",
sayName : function(){
alert(this.name);
}
};
原型的动态性
原型具有动态性,即当原型有修改时,无论实例在原型修改前创建还是修改后创建,原型修改的内容都可以在实例体现。
function Person(){
}
var Edward = new Person();
Person.prototype.sayHello = function(){
alert("Hello");
};
Edward.sayName (); //"Hello"(没有问题)
除了自定义类型,所有的原生引用类型(Object、Array、String,等等 )都采用这种模式。通过原生对象的原型,不仅可以获得所有默认方法的引用,也可以定义新方法。
重写原型之后,现有原型与之前已经存在的原型实例之间没有联系,它们引用的仍然是最初的原型。
function Person(){
}
var Edward = new Person();
Person.prototype = {
sayHi : function(){
alert("Hi");
}
};
Edward.sayHi(); //Error
原型对象的问题
因为原型中的属性都被所有实例共享,因此,所有实例在默认情况下都将取得相同的属性值。如果原型中有包含引用值的属性,当修改某一实例的该属性时,这次的修改将同步至其他实例,这将导致问题的产生。如:
function Person(){
}
Person.prototype = {
constructor : Person,
name : "Sheldon",
age : 29,
job : "Physical Scientist",
friends : ["Amy","Edward","Penny"]
sayName : function(){
alert(this.name);
}
};
var person1= new Person();
var person2 = new Person();
person1.friends.push("John");
alert(person1.friends); //"Amy,Edward,Penny,John"
alert(person2.friends); //"Amy,Edward,Penny,John"
alert(person1.friends == person2.friends) //true
这正是很少有人单独使用原型模式的原因。