由于在原型中查找值的过程是一次搜索,因此我们对原型对象所做的任何修改都能够立即从实例上反应出来–即使是先创建了实例后修改原型也照样如此。请看下面的例子.
var friend = new Person();
function Person(){}
Person.prototype.sayHi = function () {
console.log("Hi")
}
friend.sayHi();//Hi
以上代码先创建了Person的一个实例,并将其保存在person中。然后,下一条语句在Person.prototype中添加了一个方法sayHi().即使person实例是在添加新方法之前创建的,但它仍然可以访问这个新方法。其原因可以归结为实例和原型之间松散的连接关系。当我们调用friend.sayHi()时,会首先在实例中搜索名为sayHi的属性,在没有找到的情况下,会继续搜索原型。因为实例和原型的连接不过就是一个指针,而非一个副本,因此就可以在原型中找到新的sayHi属性并返回保存在那里的函数。
尽管可以随时为原型添加属性和方法,并且修改能够立即在所有对象实例中反应出来,但如果重新整个原型对象,那么情况就不一样了。我们知道,调用构造函数时会为实例添加一个指向最初原型的[[Prototype]]指针,而把原型修改为另一个对象就等于切断了构造函数与最初原型之间的联系。请记住:实例中的指针仅指向原型,而不指向构造函数。看看下面的例子。
function Person(){}
var friend = new Person();
Person.prototype={
constructor:Person,
name:"Nicholas",
age:29,
job:"Software Engineer",
sayName:function () {
console.log(this.name);
}
};
friend.sayName();//friend.sayName is not a function
在这个例子中,我们先创建了Person的一个实例,然后又重写了其原型对象。然后调用friend.sayName()时发生了错误,因为friend指向的原型中不包含以该名字命名的属性。图6-3展示了这个过程的内幕。
从图中可以看出,重写原型对象切断了现有原型与任何之前已经存在的对象实例之间的联系,它们引用的仍然是最初的原型。