2012-12-29 39 views
4

正當我認爲自己對原型繼承在JavaScript中的工作方式持保留態度時,遇到了一個我以前沒有考慮過的問題。防止構造函數的多個實例共享相同的原型屬性

看看下面的簡單的JavaScript代碼:

var Observable = function() { 
    this.events = []; 
}; 

Observable.prototype.addEvent = function (e) { 
    this.events.push(e); 
}; 

var Model = function() {}; 
Model.prototype = new Observable(); 

var appModel = new Model(); 
var taskModel = new Model(); 

appModel.addEvent('Hello'); 
taskModel.addEvent('World'); 

尋找在任appModel.eventstaskModel.events產生相同的數組:['Hello', 'World']。我期待的是每個新的Model都有自己的events陣列,儘可能清潔。的Model以下實施工作:

var Model = function() { 
    this.events = []; 
}; 
Model.prototype = new Observable(); 

然而,隨着越來越多的屬性添加到Observable這變得更加難以處理。我以爲我可以解決這個問題如下:我敢肯定,你們誰在JavaScript中更有經驗實現,這將引發一個錯誤

var Model = function() { 
    this.prototype.constructor.apply(this, arguments); 
}; 
Model.prototype = new Observable(); 

Alhtough:TypeError: Cannot read property 'constructor' of undefined

總之,我正在尋找一種方法,讓每個新的Model繼承Observable的屬性,併爲每個Model擁有自己的events。我意識到這是非常類的,但我想知道如何僅使用基於JavaScript原型的繼承來完成此操作。

值得注意的是,我看過Dean Edward的Base.js。以下作品:

var Observable = Base.extend({ 
    constructor: function() { 
    this.events = []; 
    }, 
    addEvent: function (e) { 
    this.events.push(e); 
    } 
}); 

var Model = Observable.extend({ 
    constructor: function() { 
    this.base(); 
    } 
}); 

var appModel = new Model(); 
var taskModel = new Model(); 

appModel.addEvent('Hello'); 
taskModel.addEvent('World'); 

但是下面

var Observable = Base.extend({ 
    events: [], 
    addEvent: function (e) { 
    this.events.push(e); 
    } 
}); 

var Model = Observable.extend({ 
    constructor: function() { 
    this.base(); 
    } 
}); 

var appModel = new Model(); 
var taskModel = new Model(); 

appModel.addEvent('Hello'); 
taskModel.addEvent('World'); 

除了一點,我想學習如何使用JavaScript的原型不使用類庫做到這一點。

+0

問題是.....? – HMarioD

+0

我有這個確切的問題,試圖建立一個Observable類。當然,我們不能成爲第一個在JS中構建這種類型的東西的人? –

回答

0

我在這裏明白是要每個實例有各自獨立的事件數組,如果是遵循了答案:

function Model(){ 
    this.events = []; 
    this.addEvent = function(eventName){ 
    this.events.push(eventName); 
    }; 
    this.getEvents = function(){ 
    return this.events; 
    } 
} 

var m1 = new Model; 
var m2 = new Model; 
m1.addEvent("eve-1"); 
m2.addEvent("eve-2"); 
m1.getEvents(); //["eve-1"] 
m2.getEvents(); //["eve-2"] 

在你的情況,你是直接因此添加事件到prototype沒有實例他們在所有的情況下,加...我希望這將有助於

+0

我想要做的是在共享該共同行爲的多種類型的對象中獲得共同行爲。雖然我沒有創建任何東西,只是'模型',目的是創造更多類型共享相同的功能,但不是相同的事件。保留'Observable'原型上的方法對我來說很有意義,但我想要一種方法,在我創建的每個構造函數中不必聲明this.events = [];'。 – user1937128

+0

所有那些需要共同點的東西都應該添加到原型中,並且應該像上面那樣添加這些變量事件... –

0

我試過這解決我的問題:

var Model = function() { 
    this.prototype.constructor.apply(this, arguments); 
}; 
Model.prototype = new Observable(); 

的交流圖阿爾,解決方案是這樣的:

var Model = function() { 
    Model.prototype.constructor.apply(this, arguments); 
}; 
Model.prototype = new Observable(); 

這會給每個Model自己的events陣列,以及給每個ModelObservable構造函數創建任何其他屬性。這裏的小開銷是Model.prototype.events是一個永遠不會被訪問的空數組。

0

您的第一位代碼導致Model的每個實例擁有共同的events數組的原因是因爲它們具有對Observable的單個常見實例的原型引用。換句話說,通過做

Model.prototype = new Observable(); 

你基本上是告訴JavaScript的「使Model行爲所有實例像此特定實例的Observable」。

有幾種不同的方法可以在JavaScript中正確執行原型繼承。如果您可以使用最近標準化的ECMAScript 6,您可以使用專門爲此目的而設計的新型關鍵字classextends

class Observable { 
    constructor() { 
     this.events = []; 
    } 

    addEvent() { 
     this.events.push(e); 
    } 
} 

class Model extends Observable { 
    // Model definition 
}; 

不幸的是,對ECMAScript 6的支持仍然是isn't great。 ECMAScript 5增加了Object.create,因爲(至少據我所知),它一直是繼承的首選方法。

var Observable = function() { 
    this.events = []; 
}; 

Observable.prototype.addEvent = function (e) { 
    this.events.push(e); 
}; 

var Model = function() { 
    Observable.call(this); 
}; 
Model.prototype = Object.create(Observable.prototype); 

MDN有一個很不錯的article on OOP in JavaScript使用這種技術。

相關問題