2014-05-07 49 views
3

我觀察到一個關於__proto__的行爲,這對我來說似乎很奇怪:當將__proto__更改爲各種對象時,其行爲與預期相同,但一旦將其設置爲null,將其再次更改爲另一個對象似乎沒有效果。__proto__似乎無效後分配 - 錯誤或功能?

這是實施中的錯誤還是期望的行爲?如果這是所期望的行爲,有人可以闡明爲什麼嗎?

一個例子JavaScript代碼(所有的測試都通過了罰款,直到最後一行):

p = { 
    sum: function() { 
    return this.x + this.y; 
    } 
}; 

o = { 
    x: 1, 
    y: 2 
}; 

o.sum(); // As expected: TypeError: o.sum is not a function 

// These all behave as expected: 
o.__proto__ = p; 
o.__proto__; // [object Object] 
o.__proto__.sum; // [object Function] 
o.sum(); // returns 3 :-) 

// These all behave as expected: 
o.__proto__ = {}; 
o.__proto__; // [object Object] 
o.sum(); // TypeError: o.sum is not a function 

// These all behave as expected: 
o.__proto__ = p; 
o.__proto__; // [object Object] 
o.__proto__.sum; // [object Function] 
o.sum(); // returns 3 :-) 

// Still behaves more or less as expected: 
o.__proto__ = null; 
o.__proto__; // undefined (why undefined and not null?) 
o.sum(); // TypeError: o.sum is not a function 

// Seems fine, until the last line: 
o.__proto__ = p; 
o.__proto__; // [object Object] 
o.__proto__.sum; // [object Function] 
o.sum(); // Expected 3, but... TypeError: o.sum is not a function 

我用Firefox 28.0工作;不知道其他瀏覽器如何反應。

+1

您究竟如何運行測試?我的意思是你不能在第一個TypeError之後繼續測試,那麼你是否再次使用該行註釋掉了它? –

+0

@cookie:我在網絡控制檯上逐行運行它:) – Tom

+0

我看到它發生了。似乎只要您分配'。proto__ = null',原型繼承在'o'上永久破壞。在重新分配'p'後,甚至不能使用'.hasOwnProperty()'等本地方法。雖然'__proto__'是非標準的,所以我不知道它可能被稱爲bug。 –

回答

2

問題是,Firefox中的__proto__Object.prototype上的一個實際屬性,使用getter/setter函數實現。因此,當您將__proto__o設置爲null時,您已消除整個原型鏈,其中包括__proto__屬性。

現在當您分配給__proto__時,您只是將一個新的普通屬性直接分配給o對象。


所以爲了得到__proto__的功能,你需要去Object.prototype,並借用__proto__屬性的.set方法,並使用.call允許它在o對象進行操作。

Object.getOwnPropertyDescriptor(Object.prototype, "__proto__").set.call(o, p); 

所以這個調用使用.call使得o成爲setthis值的Object.prototype.__proto__set功能,並p是被設置的值。這將使__proto__o上運行,就好像它是o的一個屬性,允許它設置內部[[Prototype]]屬性。


請注意,這隻在Firefox中測試。

+0

感謝您的解釋 - 解決方案! – Tom

+0

不客氣。 –

相關問題