当我认为我对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原型来实现这一点。
答案 0 :(得分: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
而不是实例,因此它们会添加到所有实例中...我希望这有助于
答案 1 :(得分: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
数组,并为Model
构造函数创建的每个Observable
提供任何其他属性。这里的小开销是Model.prototype.events
是一个永远不会被访问的空数组。
答案 2 :(得分:0)
你的第一段代码导致Model
的每个实例都有一个公共events
数组的原因是因为它们对Observable
的单个公共实例有一个原型引用。换句话说,通过做
Model.prototype = new Observable();
您基本上是在告诉JavaScript“让Model
的所有实例都像{strong> Observable
的一样。
在JavaScript中有几种不同的方法可以正确执行原型继承。如果您可以使用最近标准化的ECMAScript 6,则可以使用为此目的而设计的方便的新class
和extends
关键字。
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。