将复杂的层次结构推入observableArray可以创建重复的实例

时间:2013-01-25 19:41:50

标签: javascript knockout.js design-patterns

在尝试提出一个基本模型来处理我正在处理的应用程序域的所有类似实体时,我创建了:

  • 基本对象(Entity):具有一些共享属性和初始值设定项,设置为Prototype
  • 产品对象(产品):从实体“继承”。并包含“变种”列表
  • 变体对象(变体):从实体“继承”。
  

Product.prototype = new Entity();

     

Variant.prototype = new Entity();

当我运行它时,发生了一些奇怪的事情:来自“product”对象的“variants”列表最终包含两个元素,这很好,但是它们不是两个分隔“Variant”的实例,而是指向相同的记忆空间。

我做了一些调试(基于警报),以确保在填充observableArray的'for循环'期间,事情看起来很好。

var Product = function (data) {
var initial = data || {};
this.variants = ko.observableArray();
this.init(initial);
if (initial.variants != null) {
  for (var i = 0; i < initial.variants.length; i++) {

    // NOTE: this is the misterious line. Creating two instances
    //       of 'new Variant', ends up pushing a single instance. 
    this.variants.push(new Variant(initial.variants[i]));
    //-----------------------------------------------------------

    alert(this.variants()[i].name());
  }
}

我认为我缺少一些Javascript基础来弄清楚我做错了什么。

JsFiddle处的完整样本。

1 个答案:

答案 0 :(得分:1)

如果将observable放在原型上,那么它们最终会在所有实例之间共享,而不是成为他们自己独立的可观察对象。可观察的是一种在内部缓存其值的函数。因此,在这种情况下,每个实例都有相同功能的副本。

通常,您可能希望避免在原型上放置observable,尽管您当然可以放置任何其他函数(通用处理程序,订阅回调和计算的可观察读/写函数)。

如果要创建一个从具有observables的另一个继承的结构,那么可以选择使用各种“混合”类型策略之一。

例如,您可以将基础构造函数应用于兄弟对象。

var Product = function(data) {
  Entity.call(this, data); //call the Entity constructor to add observables, etc.

  //do other Product stuff here
};

然后,您可以使Product原型等于Entity原型或更好地使Product原型在其链中具有Entity原型,如:

Product.prototype = Object.create(Entity.prototype);

如果您支持较旧的浏览器,请查找Object.create shim

更新了示例:http://jsfiddle.net/rniemeyer/7AnAz/