0

In trying to come up with a basic model to handle all the similar entities for the application domain I'm working on, I created:

  • A basic object (Entity): that has some shared properties and initializers, setup as Prototype
  • A product object (Product): that "inherits" from Entity. And contains a list of "Variants"
  • A variant object (Variant): that "inherits" from Entity.

Product.prototype = new Entity();

Variant.prototype = new Entity();

When I run this, something weird happens: the "variants" list from the "product" object, ends up containing two elements, which is fine, but instead of these being two separates instances of "Variant", they point at the same memory space.

I've done some debugging (alert based), to ensure that, during the 'for loop' that fills the observableArray, things look fine.

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());
  }
}

I asume I'm missing some Javascript basics to figure out what am I doing wrong.

Heres the complete sample at JsFiddle.

Community
  • 1
  • 1
Luigi
  • 100
  • 2
  • 10

1 Answers1

1

If you put observables on a prototype, then they end up being shared across all instances rather than being their own separate observables. An observable is a function that caches its value internally. So, in this case, every instance has a copy of that same function.

Generally, you would want to avoid putting observables on the prototype, although you can certainly put any other functions (general handlers, subscription callbacks, and computed observable read/write functions).

If you want to create a structure that inherits from another that has observables, then could choose to use one of the various "mix-in" type strategies.

For example, you could apply the base constructor to the sibling object.

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

  //do other Product stuff here
};

You can then make the Product prototype equal the Entity prototype or better make the Product prototype have the Entity prototype in its chain like:

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

If you are supporting older browsers, then look for an Object.create shim.

Updated sample: http://jsfiddle.net/rniemeyer/7AnAz/

Community
  • 1
  • 1
RP Niemeyer
  • 114,592
  • 18
  • 291
  • 211