2012-07-28 72 views
3

我在計算原型鏈如何設置給定以下代碼時遇到了一些問題。在通過Object.create創建的對象上設置原型

var Model = { 
    prototype: { 
     init: function(){}, 
     log: function(){ console.log('instance method log was called') } 
    }, 
    log: function(){ console.log('class method log was called') }, 
    create: function() { 
     var object = Object.create(this); 
     object.parent = this; 
     object.prototype = object.fn = Object.create(this.prototype); 
     return object; 
    }, 
    init: function() { 
     var instance = Object.create(this.prototype); 
     instance.parent = this; 
     instance.init.apply(instance, arguments); 
     return instance; 
    } 
} 

var User = Model.create(); 
User.log(); // 'class method log was called' 

// create a new method after creation 
Model.warn = function() { console.warn('warn was called') } 

User.warn() // 'warn was called' 

var user = User.init(); 
user.log(); // 'instance method log was called' 

特別是此行讓我困惑的創建方法:

object.prototype = object.fn = Object.create(this.prototype); 

我瞭解如何創建方法是創建一個新的對象是誰的原型點回模式,但倒數第二行似乎覆寫帶有新對象的原型(Model.prototype)。但是,似乎原始原型仍然完好無損,因爲即使在創建新對象後,我仍然可以向模型中添加方法,並且新對象仍然可以訪問它。

有人可以說明實際發生的情況嗎?

編輯 - 我應該指出,這個代碼來自的JavaScript的Web應用程序由O'Reilly

+1

對於什麼讓你感到困惑,有點不清楚,但是也許你認爲''this''和'object'指的是'Model.create'中的同樣的東西。如果是這樣,他們不是。 'this'是對'Model'的引用,但'object'是對從Object.create(this)創建的新對象的引用。所以,當你做'object.prototype = ... whatever'時,你不會覆蓋'Model.prototype',但是你可以通過將'object'原型鏈中存在的'.prototype'屬性隱藏*一個屬性直接在'object'上。 – 2012-07-28 20:12:40

+0

我明白'this'是Model和'object'是一個新對象,而讓我困惑的是最初Object.create(this)將新對象原型設置爲'Model',但後來幾行對象。原型重置爲Object.create(this.prototype)。這是我不明白的路線。對我來說,它看起來像object.prototype現在設置爲一個對象的原型設置爲Model.prototype(init和日誌功能),但返回的對象,而不是直接訪問模型上的方法。 – jhummel 2012-07-29 02:53:31

+2

我想我看到了什麼讓你感到困惑。在'object'上設置的'.prototype'屬性與原型鏈本身無關。一旦你創建了一個對象,就不可能改變原型鏈。所以當一個值被寫入'object.prototype'時,它不會干涉'object'和'Model'之間的關係。設置'.prototype'屬性的唯一時間對原型鏈有影響,就是當你改變''時。原型'屬性的構造函數,然後只有將來的構造函數產生的對象纔會受到該變化的影響。 – 2012-07-29 03:22:31

回答

2

確定。所以只是刪除干擾代碼,你問這個代碼:

var Model = { 
    prototype: {}, 
    create: function() { 
     var object = Object.create(this); 
     object.prototype = Object.create(this.prototype); 
     return object; 
    } 
}; 

Model.create()函數是簡單的,它會創建一個新的對象誰擴展(原型)模型的第一線。

但由於下一行覆蓋了對象「原型」屬性,因此您被拒絕。它不是對象的原型,對象原型仍然是Model,它存儲在名爲[[Prototype]]的隱藏屬性中,代碼正在修改的屬性與對象的[[Prototype]]沒有任何關係,它只具有相同的屬性名稱。讓我們改變名稱來理解它,這將是相同的:

var Model = { 
    blablabla: {}, 
    create: function() { 
     var object = Object.create(this); 
     object.blablabla = Object.create(this.blablabla); 
     return object; 
    } 
}; 

它擴展Model.blablabla所以當你改變object.blablabla它不會影響Model.blablabla。

var SubModel = Model.create(); 
SubModel.blablabla.newMethod = function() { }; 
console.log(Model.blablabla.newMethod); // undefined 

很多時候爲字段選擇正確的名稱比看起來更重要。