2010-09-29 62 views
2

基本上所有關於JavaScript中成員枚舉的人都主張使用hasOwnProperty方法來避免使用原型鏈。我關於JavaScript的原型繼承和hasOwnProperty方法的困境

我知道這是防禦性編程的一種形式,以防止對已添加的成員(例如Object.prototype)進行迭代。但其他遺傳成員呢?比如說,原型鏈中非常接近的成員......實際上你想要枚舉的成員。

比方說,我有以下幾點:

var beget = function (o) { // http://javascript.crockford.com/prototypal.html 
    function F() {}; 
    F.prototype = o; 
    return new F(); 
}; 

var john = { name: 'john', surname: 'grech' }, 
    mary = beget(john), 
    p; 

mary.age = 42; //augmenting 'mary' 

// 'surname' in mary    => true 
// mary.hasOwnProperty('surname') => false 

for (p in mary) { 
    //skipping over non-direct members, meaning that we also skip members 
    //inherited from 'john' 
    if (!mary.hasOwnProperty(p)) { 
     continue; 
    } 
    console.log(p); 
} 

在上面的例子中,只有age會顯示出來,因爲agemary唯一的直接成員......其他兩名成員,namesurname ,是原型鏈。

但顯然,我希望所有3個成員迭代在for..in構造;但如果您刪除hasOwnProperty,則可以從Object.Prototype獲得成員,如果有人向其添加功能的話。


所以這是我的困境。

您是否將原型繼承與hasOwnProperty方法結合使用,但會導致在枚舉過程中鏈接太遠的成員面臨風險?

或者您是否使用其他形式的繼承,將成員直接添加到對象而不是原型?

回答

3

嗯。你說的「原型鏈非常接近」,但實際上,它意味着什麼非常接近?三個級別是「接近」還是「遠」?

無論如何,你可以改變一下beget函​​數,併爲每個對象實現自己的hasOwnProperty函數,這些函數只會經過原型鏈直到Object級別。這將解決您通過不使用hasOwnProperty獲取添加到Object.prototype的成員的難題。附代碼如下:

var beget = function (o) { // http://javascript.crockford.com/prototypal.html 
    function F() { 
     this.hasOwnProperty = function(key) { 
      return (key != "hasOwnProperty" 
       && Object.prototype.hasOwnProperty.call(this, key) 
       || o.hasOwnProperty(key) 
      ); 
     } 
    }; 

    F.prototype = o; 
    return new F(); 
}; 

var john = { name: 'john', surname: 'grech' }, 
    mary = beget(john), 
    p = beget(mary); 

mary.age = 42; //augmenting 'mary' 
mary.name = "mary"; 
p.size = "38"; 

// testing prototype of Object. 
Object.prototype.not_own = function(){} 

for(var i in p) { 
    console.debug('Key',i, p.hasOwnProperty(i)); 
} 

// p.hasOwnProperty("size"); // -> true 
// p.hasOwnProperty("age");  // -> true 
// p.hasOwnProperty("name"); // -> true 
// p.hasOwnProperty("not_own"); // -> false 
0

如果您需要遍歷對象的原型鏈,則可以使用hasOwnProperty跳過直接成員(如您所說)。這當然也會通過添加到該對象原型的其他成員(Object.Prototype等)進行迭代。沒有辦法避免這種情況。

這就像要求如何避免枚舉某個car = {yellow, green, black}對象的某些成員(僞代碼)......您不......您只是根據它們的值跳過某些成員。


添加成員直接一個對象是不是真的繼承的一種形式,當然,除非你創建一個使用begetObject()技術的對象......因爲它使用了原型添加成員。

+0

我沒有說通過增加直接成員來增加對象就是繼承。但是,使用'beget'函數,您正在使用原型繼承,因爲您'繼承'的類的成員被添加到原型。 – 2010-09-29 09:26:06

+0

就這樣說,你的回答並沒有讓我更接近理解應該做什麼。 – 2010-09-29 09:26:33

+0

@Andreas:你想要做什麼並不是很清楚。如果你試圖遍歷一個對象,我回答了你的問題。如果你試圖使用直接成員和begetObject()來進行繼承,那麼你的問題是什麼? – 2010-09-29 09:33:03