hasOwnProperty 函數&&for in 循環

hasOwnProperty函數

為了判斷一個對象是否包含自定義屬性而不是原型鏈上的屬性, 我們需要使用繼承自 Object.prototype 的 hasOwnProperty 方法。

hasOwnProperty 是 JavaScript 中唯一一個處理屬性但是查找原型鏈的函數。

注意: 通過判斷一個屬性是否undefined是不夠的。 因為一個屬性可能確實存在,只不過它的值被設置為undefined。

// 修改Object.prototype
Object.prototype.bar = 1; 
var foo = {goo: undefined};
foo.bar; // 1
'bar' in foo; // true
foo.hasOwnProperty('bar'); // false
foo.hasOwnProperty('goo'); // true

只有 hasOwnProperty 可以給出正確和期望的結果,這在遍歷對象的屬性時會很有用。 沒有其它方法可以用來排除原型鏈上的屬性,而不是定義在對象自身上的屬性。

hasOwnProperty 作為屬性

JavaScript 不會保護 hasOwnProperty 被非法占用,因此如果一個對象碰巧存在這個屬性, 就需要使用外部的 hasOwnProperty 函數來獲取正確的結果。

var foo = {
    hasOwnProperty: function() {
        return false;
    },
    bar: 'Here be dragons'
};
foo.hasOwnProperty('bar'); // 總是返回 false
// 使用其它對象的 hasOwnProperty,并將其上下文設置為foo
({}).hasOwnProperty.call(foo, 'bar'); // true
結論

當檢查對象上某個屬性是否存在時,hasOwnProperty 是唯一可用的方法。 同時在使用 for in loop 遍歷對象時,推薦總是使用 hasOwnProperty 方法, 這將會避免原型對象擴展帶來的干擾。

for in 循環

和 in 操作符一樣,for in 循環同樣在查找對象屬性時遍歷原型鏈上的所有屬性。
注意: for in 循環不會遍歷那些 enumerable 設置為false 的屬性;比如數組的length 屬性。

// 修改 Object.prototype
Object.prototype.bar = 1;
var foo = {moo: 2};
for(var i in foo) {
    console.log(i); // 輸出兩個屬性:bar 和 moo
}

由于不可能改變 for in 自身的行為,因此有必要過濾出那些不希望出現在循環體中的屬性, 這可以通過 Object.prototype 原型上的 hasOwnProperty
函數來完成。

使用 hasOwnProperty 過濾

注意: 由于 for in 總是要遍歷整個原型鏈,因此如果一個對象的繼承層次太深的話會影響性能。

// foo 變量是上例中的
for(var i in foo) {
    if (foo.hasOwnProperty(i)) {
        console.log(i);
    }
}

這個版本的代碼是唯一正確的寫法。由于我們使用了 hasOwnProperty,所以這次輸出 moo。 如果不使用 hasOwnProperty,則這段代碼在原生對象原型(比如 Object.prototype)被擴展時可能會出錯。
一個廣泛使用的類庫 Prototype 就擴展了原生的 JavaScript 對象。 因此,當這個類庫被包含在頁面中時,不使用 hasOwnProperty 過濾的 for in 循環難免會出問題。

總結

推薦總是使用 hasOwnProperty。不要對代碼運行的環境做任何假設,不要假設原生對象是否已經被擴展了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容