2011-10-01 55 views
2

改變可能有人在一個合理的方式給我講解一下:原型對象可以從例如

function One() {} 

One.prototype.obj = { key: 'value' }; 
One.prototype.str = 'string'; 

var inst1 = new One(), 
    inst2 = new One(); 

// now let’s change some things in our second instance 

inst2.obj.key = 'buh!'; 
inst2.str = 'buh!'; 

// ok, so what happens to our other instance? 

console.log(inst1.str); // Yields 'string' (unaffected, expected) 
console.log(inst1.obj.key); // Yields 'buh!' (!!) 

console.log(One.prototype.obj.key); // is also 'buh!' 

看來,如果一個原型包含對象,您創建使用new關鍵字的實例有對象,但如果你改變它,你也改變原型對象,從而影響所有的實例,如兄弟姐妹繼承模式...

這是它的方式工作?

+0

是的,如果你想禁用它,你可以凍結一個對象:'Object.freeze(One.prototype.obj);'。 – pimvdb

+0

不錯,不知道凍結。但瀏覽器支持似乎很窄http://kangax.github.com/es5-compat-table/ – David

+0

@大衛所有當前的瀏覽器實現'freeze'! ':P' –

回答

2

實際上,JavaScript不從原型複製任何東西。你在原型上定義的所有東西只存在一次(在原型本身上)並被重用,因爲同一個原型實例被傳遞給所有對象。

當您訪問對象的屬性時,該對象將檢查它是否在其自身上定義。如果是,它將返回與該屬性關聯的值。如果不是,它會將呼叫委託給它的原型,誰將從現在起對發生的事情負責。這就是爲什麼Javascript中的「繼承」(代碼重用)更好的稱爲委派。

寫訪問有點不同。如果你在對象上設置了一個屬性,它會在本地「映射」這個值。這就是str屬性不受影響的原因,它實際上是在inst2對象上定義的。但是,如果您delete inst2.str並做另一個console.log(inst2.str)您會注意到它將返回舊值。

PS: 如果你想有一個方法來防止這種情況發生看看這個教程:http://kevlindev.com/tutorials/javascript/inheritance/index.htm

我建議你閱讀了整個事情,但如果你只是想肉看到KevLinDev.extend功能「創建子類」部分。

2

總之,是的。 Javascript不會爲您隱式複製對象,因此當您在obj處創建對象字面值時,One類的所有實例都只是通過引用來引用它。相反,你需要在構造函數中動態創建obj對象:

function One(){ 
    this.obj = {key:'value'}; 
} 

參見:javascript multidimensional object