[英]Preventing multiple instances of a constructor function from sharing the same prototype properties
當我認為我對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.events
或taskModel.events
生成相同的數組: ['Hello', 'World']
。 我要做的是讓每個新Model
盡可能干凈地擁有自己的events
數組。 以下Model
實現:
var Model = function () {
this.events = [];
};
Model.prototype = new Observable();
但是,隨着向Observable
添加更多屬性,這變得更加笨拙。 我想我可以解決這個問題如下:
var Model = function () {
this.prototype.constructor.apply(this, arguments);
};
Model.prototype = new Observable();
雖然我很確定那些在JavaScript方面經驗豐富的人意識到這會引發錯誤: 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原型來做到這一點。
我在這里理解的是,你希望每個實例都有自己獨立的事件數組,如果是這樣,請按照以下答案:
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
而不是實例,因此它們被添加到所有實例中...我希望這應該有所幫助
我試過這個來解決我的問題:
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
數組,並為每個Model
提供Observable
構造函數創建的任何其他屬性。 這里的小開銷是Model.prototype.events
是一個永遠不會被訪問的空數組。
你在那里的第一個代碼導致每個Model
實例都有一個公共events
數組的原因是因為它們有一個對Observable
的單個公共實例的原型引用。 換句話說,通過做
Model.prototype = new Observable();
您基本上是在告訴JavaScript“使Model
所有實例都像Observable
這個特定實例一樣”。
在JavaScript中有幾種不同的方法可以正確執行原型繼承。 如果您可以使用最近標准化的ECMAScript 6,您可以使用方便的新class
並extends
為此目的而設計的關鍵字。
class Observable {
constructor() {
this.events = [];
}
addEvent() {
this.events.push(e);
}
}
class Model extends Observable {
// Model definition
};
不幸的是,對ECMAScript 6的支持仍然不是很好 。 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使用這種技術在JavaScript中有一篇關於OOP的非常好的文章 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.