簡體   English   中英

防止構造函數的多個實例共享相同的原型屬性

[英]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.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

總之,我正在尋找一種方法,讓每個新ModelObservable繼承屬性,並為每個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,您可以使用方便的新classextends為此目的而設計的關鍵字。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM