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这变得更加笨拙。我想我可以按如下方式解决这个问题:

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

尽管我确信那些在 JavaScript 方面更有经验的人意识到这会引发错误:TypeError: Cannot read property 'constructor' of undefined.

总之,我正在寻找一种方法让每个新Model的继承属性,Observable并让每个新Modelevents. 我意识到这非常类似于类,但我想知道如何仅使用基于 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 原型来做到这一点。

4

3 回答 3

0

What I have understood here is that you want each instance to have their separate events array, If so follow the answer:

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"]

In your case you are adding events directly to the prototype not the instances hence they are added across all the instances...I hope this should help

于 2012-12-29T22:28:56.260 回答
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是一个永远不会访问的空数组。

于 2012-12-29T23:18:03.543 回答
0

你的第一段代码导致每个实例Model都有一个公共events数组的原因是因为它们有一个对单个公共实例的原型引用Observable。换句话说,通过做

Model.prototype = new Observable();

您基本上是在告诉 JavaScript “使所有实例的Model行为都像这个特定的实例Observable

有几种不同的方法可以在 JavaScript 中正确执行原型继承。如果您可以使用最近标准化的 ECMAScript 6,您可以使用为此目的而设计的方便的 newclass和关键字。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的非常好的文章。

于 2016-01-21T23:10:54.013 回答