原型 in 操作符 與keys 方法
有兩種方式使用 in 操作符:單獨使用和在 for-in 迴圈中使用。在單獨使用時, in 操作符會在通過物件能夠訪問給定屬性時返回 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 alert("name" in person1); //true person1.name = "Greg"; alert(person1.name); //"Greg" —— 來自例項 alert(person1.hasOwnProperty("name")); //true alert("name" in person1); //true alert(person2.name); //"Nicholas" —— 來自原型 alert(person2.hasOwnProperty("name")); //false alert("name" in person2); //true delete person1.name; alert(person1.name); //"Nicholas" —— 來自原型 alert(person1.hasOwnProperty("name")); //false alert("name" in person1); //true
在以上程式碼執行的整個過程中, name 屬性要麼是直接在物件上訪問到的,要麼是通過原型訪問到的。因此,呼叫"name" in person1 始終都返回 true,無論該屬性存在於例項中還是存在於原型中。同時使用 hasOwnProperty()方法和 in 操作符,就可以確定該屬性到底是存在於物件中,還是存在於原型中,如下所示。
function hasPrototypeProperty(object, name){
return !object.hasOwnProperty(name) && (name in object);
}
由於 in 操作符只要通過物件能夠訪問到屬性就返回 true, hasOwnProperty()只在屬性存在於例項中時才返回 true,因此只要 in 操作符返回 true 而 hasOwnProperty()返回 false,就可以確定屬性是原型中的屬性。下面來看一看上面定義的函式 hasPrototypeProperty()的用法。
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person = new Person(); alert(hasPrototypeProperty(person, "name")); //true person.name = "Greg"; alert(hasPrototypeProperty(person, "name")); //false
在這裡, name 屬性先是存在於原型中,因此 hasPrototypeProperty()返回 true。當在例項中重寫 name 屬性後,該屬性就存在於例項中了,因此 hasPrototypeProperty()返回 false。即使原型中仍然有 name 屬性,但由於現在例項中也有了這個屬性,因此原型中的 name 屬性就用不到了。在使用 for-in 迴圈時,返回的是所有能夠通過物件訪問的、可列舉的(enumerated)屬性,其中既包括存在於例項中的屬性,也包括存在於原型中的屬性。遮蔽了原型中不可列舉屬性(即將[[Enumerable]]標記為 false 的屬性)的例項屬性也會在 for-in 迴圈中返回,因為根據規定,所有開發人員定義的屬性都是可列舉的——只有在 IE8 及更早版本中例外。
keys用法
要取得物件上所有可列舉的例項屬性,可以使用 ECMAScript 5 的 Object.keys()方法。這個方法接收一個物件作為引數,返回一個包含所有可列舉屬性的字串陣列。例如:
function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var keys = Object.keys(Person.prototype);
alert(keys); //"name,age,job,sayName"
var p1 = new Person();
p1.name = "Rob";
p1.age = 31;
var p1keys = Object.keys(p1);
alert(p1keys); //"name,age"
這裡,變數 keys 中將儲存一個數組,陣列中是字串"name"、 "age"、 "job"和"sayName"。這個順序也是它們在 for-in 迴圈中出現的順序。如果是通過 Person 的例項呼叫,則 Object.keys()返回的陣列只包含"name"和"age"這兩個例項屬性。如果你想要得到所有例項屬性,無論它是否可列舉,都可以使用 Object.getOwnPropertyNames()方法。
var keys = Object.getOwnPropertyNames(Person.prototype);
alert(keys); //"constructor,name,age,job,sayName"
注意結果中包含了不可列舉的 constructor 屬性。 Object.keys()和 Object.getOwnPropertyNames()方法都可以用來替代 for-in 迴圈。 支援這兩個方法的瀏覽器有 IE9+、 Firefox 4+、 Safari 5+、 Opera12+和 Chrome。