它不是被修改的原型,而是您放在原型上的config
對象。這是正確的行爲,當您創建新實例時,原型引用的對象不會被複制。 f1.config === f2.config
,它們指向的是相同的對象。
方式的原型鏈作品get
操作是這樣的:
- 你做一些事情,查找屬性的對象。說,
this.config
。
- 通過該名稱檢查對象本身是否具有屬性。如果是這樣,則使用該屬性的副本並返回其值。在你的情況下,該對象沒有自己的
config
,所以我們繼續下一步。
- 檢查對象的原型,看它是否具有該屬性它。如果是這樣,則使用該屬性的副本並返回其值。在你的情況下,這是真的,因爲原型有財產。但爲了完整性:
- 重複步驟3,根據需要繼續(向下?)原型鏈。
- 如果找不到物業根本不在,請返回
undefined
。
(set
操作的工作方式不同;一個set
操作總是更新或創建它被設置上,從來沒有進一步下跌的對象上的屬性[?UP]原型鏈)
所以你的情況,由於您的實例沒有config
屬性,因此我們轉到原型。由於的原型具有config
屬性,因此使用它。該屬性的值是一個對象引用,因此如果更改對象(通過分配給其中一個屬性),它將被更改,其他任何也使用該對象的對象將會看到該更改。
另一種方式來看待它是做一個圖:
+------+ +------+
| f1 | | f2 |
+------+ +------+
| |
+------+-------+
|
v
+--------------------+ +--------+
| [[Proto]] assigned | | config |
| via `new f` |------>| object |
+--------------------+ +--------+
|
+-------+-------+
| |
V v
+------------+ +------------+
| a property | | b property |
+------------+ +------------+
另想起來方式是讓功能和原型出完全的方式:
var pseudoProto = {}; // A stand-in for the prototype...
pseudoProto.config = { // ...with `config` on it
a: 'a',
b: 'b'
};
var f1 = {}; // A blank object...
f1.pseudo = pseudoProto; // ...referencing `pseudoProto`
var f2 = {}; // Another blank object...
f2.pseudo = pseudoProto; // ...also referencing `pseudoProto`
f1.pseudo.config.b = "bb"; // Change the `b` property on `config`
console.log(f2.pseudo.config.b); // Logs "bb", of course
以非常真實的方式,這就是通過new f()
在封面下發生的事情。您不能直接訪問指向原型的f1
和f2
實例的屬性(規範將其稱爲[[Proto]]
屬性),但它是真實的,而且它確實存在。 [僅供參考:ECMAScript規範的latest version可讓我們直接使用[[Proto]]
屬性執行一些操作,例如使用特定的[[Proto]]
(不通過函數)創建原始對象,但仍不能直接訪問屬性本身。]
有很多次你希望所有的實例共享同一個對象(例如函數對象!),所以原型是這些對象引用的正確位置;但是如果您希望每個實例都擁有它自己的副本,則需要在構造函數中創建該對象。你的情況:
var f = function(b){
this.config = {
a: 'a',
b: b
};
}
var f1 = new f('bb');
console.log(f1.config);
var f2 = new f('bbb');
console.log(f2.config);
// Logs
// { a: 'a', b: 'bb' }
// { a: 'a', b: 'bbb' }
(請注意,我搬到了console.log
報表,所以我們看到的結果是在年底,而不是一箇中間狀態。)
用於ASCII藝術的+1 – 2011-03-08 17:35:35