雖然可以通過對象實例訪問保存在原型中的值,但卻不能通過對象實例重寫原型中的值。如果我們
在實例中添加了一個屬性,而該屬性與實例原型中的一個屬性同名,那我們就在實例中創建該屬性,該
屬性將會屏蔽原型中的那個屬性。
如下例子:
function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
var person2 = new Person();
person1.name = "Greg";
alert(person1.name); //"Greg"——來自實例
alert(person2.name); //"Nicholas"——來自原型
在這個例子中,person1 的 name 被一個新值給屏蔽了。但無論訪問 person1.name 還是訪問person2.name 都能夠正常地返回值,即分別是"Greg"(來自對象實例)和"Nicholas"(來自原型)。當在 alert()中訪問 person1.name 時,需要讀取它的值,因此就會在這個實例上搜索一個名為 name的屬性。這個屬性確實存在,於是就返回它的值而不必再搜索原型了。當以同樣的方式訪問 person2. name 時,並沒有在實例上發現該屬性,因此就會繼續搜索原型,結果在那里找到了 name 屬性。
當為對象實例添加一個屬性時,這個屬性就會屏蔽原型對象中保存的同名屬性;換句話說,添加這個屬性只會阻止我們訪問原型中的那個屬性,但不會修改那個屬性。即使將這個屬性設置為null,也只會在實例中設置這個屬性,而不會恢復其指向原型的鏈接。不過,使用delete操作符則可以完全刪除實例屬性,從而讓我們能夠重新訪問原型中的屬性。如下所示:
function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
var person2 = new Person();
person1.name = "Greg";
alert(person1.name); //"Greg"——來自實例
alert(person2.name); //"Nicholas"——來自原型
delete person1.name;
alert(person1.name); //"Nicholas"——來自原型
在這個修改后的例子中,我們使用 delete 操作符刪除了 person1.name,之前它保存的"Greg"值屏蔽了同名的原型屬性。把它刪除以后,就恢復了對原型中 name 屬性的連接。因此,接下來再調用person1.name 時,返回的就是原型中 name 屬性的值了。
使用 hasOwnProperty()方法可以檢測一個屬性是存在於實例中,還是存在於原型中。這個方法(不要忘了它是從 Object 繼承來的)只在給定屬性存在於對象實例中時,才會返回 true。
function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
var person2 = new Person();
alert(person1.hasOwnProperty("name")); //false
person1.name = "Greg";
alert(person1.name); //"Greg"——來自實例
alert(person1.hasOwnProperty("name")); //true
alert(person2.name); //"Nicholas"——來自原型
alert(person2.hasOwnProperty("name")); //false
delete person1.name;
alert(person1.name); //"Nicholas"——來自原型
alert(person1.hasOwnProperty("name")); //false
通過使用 hasOwnProperty()方法,什么時候訪問的是實例屬性,什么時候訪問的是原型屬性就一清二楚了。調用 person1.hasOwnProperty( "name")時,只有當 person1 重寫 name 屬性后才會返回 true,因為只有這時候 name 才是一個實例屬性,而非原型屬性。
前面例子中每添加一個屬性和方法就要敲一遍 Person.prototype。為減少不必要的輸入,也為了從視覺上更好地封裝原型的功能,更常見的做法是用一個包含所有屬性和方法的對象字面量來重寫整個原型對象,如下面的例子所示。
function Person(){
}
Person.prototype = {
name : "Nicholas",
age : 29,
job: "Software Engineer",
sayName : function () {
alert(this.name);
}
};