2011-03-08 57 views

回答

9

它不是被修改的原型,而是您放在原型上的config對象。這是正確的行爲,當您創建新實例時,原型引用的對象不會被複制。 f1.config === f2.config,它們指向的是相同的對象。

方式的原型鏈作品get操作是這樣的:

  1. 你做一些事情,查找屬性的對象。說,this.config
  2. 通過該名稱檢查對象本身是否具有屬性。如果是這樣,則使用該屬性的副本並返回其值。在你的情況下,該對象沒有自己的config,所以我們繼續下一步。
  3. 檢查對象的原型,看它是否具有該屬性。如果是這樣,則使用該屬性的副本並返回其值。在你的情況下,這是真的,因爲原型有財產。但爲了完整性:
  4. 重複步驟3,根據需要繼續(向下?)原型鏈。
  5. 如果找不到物業根本不在,請返回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()在封面下發生的事情。您不能直接訪問指向原型的f1f2實例的屬性(規範將其稱爲[[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報表,所以我們看到的結果是在年底,而不是一箇中間狀態。)

+0

用於ASCII藝術的+1 – 2011-03-08 17:35:35

0

這裏是一個展示了一個很好的CoffeeScript例子問題:

Person = class 
    config: 
    name: "sin nombre" 
    constructor: (config={}) -> 
    @config.name = config.name if config.name? 
    getName: -> @config.name 

Human = class extends Person 

ben = new Human(name: 'Ben') 
sonny = new Human() 
alert ben.getName() 
alert sonny.getName() 

並將溶液:

Person = class 
    config: 
    name: "sin nombre" 
    constructor: (config={}) -> 
    @config = {} 
    @config[key] = value for own key, value of Person::config 
    @config.name = config.name if config.name? 
    getName: -> @config.name 

Human = class extends Person 

ben = new Human(name: 'Ben') 
sonny = new Human() 
alert ben.getName() 
alert sonny.getName()