2012-05-07 50 views
15

Mozilla聲稱它會在__proto__一段時間後刪除(〜2008),並且它仍然在瀏覽器中。它是否仍然會被棄用?它適用於Opera,Safari(我認爲)和Chrome。我不需要擔心IE,所以我很樂意繼續使用它。__proto__,它何時會消失?備擇方案?

不過,我不希望我的代碼,停一天的工作,所以對我的問題:

__proto__允許死的簡單繼承:

a.__proto__ = {'a':'test'} 

反正我有可以複製這個以符合標準的方式?我知道存在功能性繼承,這很醜陋,並且使我只想創建一個原型鏈的事實過度複雜化。只是想知道是否有巫師解決了這個問題。

感謝

+3

看起來'__proto__'可能在下一個ECMAScript中被標準化。直到最終確定後才能完全確定。 http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts ...至少在附件B,Web瀏覽器附加功能的當前草案中引用了它。 –

回答

22

注意:改變__proto__的值是不好的做法。這種做法受到JavaScript創始人Brendan Eich等人的強烈譴責。事實上__proto__屬性已經完全從像Rhino這樣的幾個JavaScript引擎中刪除。如果您想知道爲什麼然後閱讀Brendan Eich的following comment

更新:瀏覽器不會刪除__proto__屬性。實際上,ECMAScript Harmony現在已對__proto__屬性和setPrototypeOf函數進行了標準化。 __proto__屬性僅受傳統原因支持。強烈建議您使用setPrototypeOfgetPrototypeOf而不是__proto__

警告:雖然setPrototypeOf現在是一個標準,你仍然從因爲變異的對象的原型總是殺死優化,使你的代碼慢用它氣餒。另外,使用setPrototypeOf通常代表質量差的代碼。


您不需要擔心現有的代碼在一天內無法工作。 __proto__屬性是留在這裏。

現在,對於手頭的問題。我們希望做一些類似的以符合標準的方法:

var a = { 
    b: "ok" 
}; 

a.__proto__ = { 
    a: "test" 
}; 

alert(a.a); // alerts test 
alert(a.b); // alerts ok 

顯然,你不能使用Object.create,因爲我們沒有創造一個新的對象來實現這個目的。我們只是試圖改變給定對象的內部[[proto]]屬性。問題在於,一旦創建對象,就不可能更改對象的內部[[proto]]屬性(除非通過使用我們試圖避免的__proto__)。

因此,要解決這個問題,我寫了一個簡單的函數(請注意,它適用於所有對象,除了功能):

function setPrototypeOf(obj, proto) { 
    var result = Object.create(proto); 
    var names = Object.getOwnPropertyNames(obj); 
    var getProp = Object.getOwnPropertyDescriptor; 
    var setProp = Object.defineProperty; 
    var length = names.length; 
    var index = 0; 

    while (index < length) { 
     var name = names[index++]; 
     setProp(result, name, getProp(obj, name)); 
    } 

    return result; 
} 

所以我們現在可以更改任何對象的原型創建完畢後,如下所示(注意,我們實際上並沒有改變對象的內部[[proto]]屬性,而是創建一個新的對象具有相同的屬性定對象從給定的原型繼承):

var a = { 
 
    b: "ok" 
 
}; 
 

 
a = setPrototypeOf(a, { 
 
    a: "test" 
 
}); 
 

 
alert(a.a); // alerts test 
 
alert(a.b); // alerts ok
<script> 
 
function setPrototypeOf(obj, proto) { 
 
    var result = Object.create(proto); 
 
    var names = Object.getOwnPropertyNames(obj); 
 
    var getProp = Object.getOwnPropertyDescriptor; 
 
    var setProp = Object.defineProperty; 
 
    var length = names.length; 
 
    var index = 0; 
 

 
    while (index < length) { 
 
     var name = names[index++]; 
 
     setProp(result, name, getProp(obj, name)); 
 
    } 
 

 
    return result; 
 
} 
 
</script>

簡單高效(並且我們沒有使用__proto__屬性)。

+0

很棒的回答。謝謝! – jdw

+2

根據標準組織和JS引擎實現者的明確建議,你實際上在告訴人們編寫破損的代碼。根據這樣的錯誤,Windows API和內部部件如何變得如此混亂。如果你能避免它,你真的不應該。我真的不認爲你應該沒有任何警告地推薦它。你和我都不是比這個語言的規範或實現者更高的權威。請記住:實際上並沒有包含'__proto__'的JavaScript版本 - 這是一些內部細節,有些實現恰好暴露出來。 – Chuck

+7

@Chuck,'__proto__'屬性被認爲是上一個指出的@cliffsofinsanity在下一個JavaScript版本中的標準。實施者建議不要使用它,因爲它還不是一個標準。因此它可能不適用於所有JavaScript引擎。理解爲什麼不建議使用某個特徵而不是僅僅批評別人總是一個好主意。因爲所有主流瀏覽器都支持它,所以在網絡上使用'__proto__'屬性是完全沒問題的。我沒有看到使用它的任何警告,除非它在犀牛中不起作用。它與Windows無關。 –

1

我怎麼沒看到:

var a = {}; 
a.__proto__ = A; // A is object because no constructor is needed 

簡單比:如果你不

var a = new A(); // A is Constructor function 

現在設立在後一種情況下可以更加詳細」 t需要一個構造函數,但在這種情況下,您可以將它自動化爲一樣簡單:

var A = Constructor({ 
    method: function(){} 
}); // A is function, meant to be used with new 

相比:

var A = { 
    method: function(){} 
}; //A is object, meant to be set as __proto__ 

如果你需要一些初始化的邏輯,它最終可能會更易於只是用 在構造函數必須反正宣佈

+0

對於init邏輯,可以使用工廠而不是依賴構造函數。你需要深入一點才能看到價值。如果你的兩個版本有原型,Object.create更簡單一些。請參閱:function Constructor(){}; Constructor.prototype = {/ * methods * /}; var newObject = new Constructor(); ** VS ** var proto = {/ * methods * /}; var newObject = Object.create(proto);.我只是用較少的代碼創建了一個新的原型對象,而不是定義我的經典繼承。 – Drew

+1

@Drew首先,第一個不使用經典繼承。其次,只有一次性設置成本需要更多代碼,實際創建對象不僅僅是更少的代碼,而是允許初始化邏輯而不創建單獨的工廠。請記住,JS中的構造函數像任何其他函數一樣運行,它不像使用古典語言的構造函數那樣受到限制,所以用這些語言創建工廠的很多原因不適用於js。 – Esailija

7

正常方式我認爲Mozilla希望實現的目標是非標準化,因此實現者完全可以將其移除。

做原型鏈的更簡潔的方法是Object.create。你的代碼的等效,創建一個對象a與原型{'a': 'test'}是:

a = Object.create({'a':'test'}) 

也有墊片來模仿這種功能在不支持它的瀏覽器,如果你需要一個工作,這是直接與__proto__混淆的另一個優點。

+0

我不認爲OP想用一個給定的原型創建一個新的對象。我認爲他想改變現有對象的原型而不修改'__proto__'。 –

+1

@AaditMShah:他的描述是「只是想創建一個原型鏈」,而不是「功能的繼承」。這表明他想要純原型繼承,這是Object.create的用途。動態旋轉原型是有用的,但不是通常需要的。 – Chuck

+0

另外,通過重新分配原型來改變對象的速度要慢得多,並且不鼓勵。 Object.create是更快的方法。 –