Question

function Entity() {
    this.a = {a: 4};
    this.b = 5;
}

function Thing() {}
Thing.prototype = new Entity;

var thing1 = new Thing;
thing1.a.a = 3;
thing1.b = 4;
var thing2 = new Thing;
console.log(thing2.a.a); // prints 3 instead of 4. I would like 4.
console.log(thing2.b) // prints 5 as wanted

I'm having difficulty with setting prototypical inheritance in javascript. Ideally I want both thing1 and thing2 to have their own clean copy of the "new Entity prototype".

using this.__proto__ is something I want to avoid

[Edit]

I have a rough idea of how this working.

Setting thing1.b sets the b property on the Thing instance. which does not touch the Entity.b defined in the prototype chain.

Where as setting thing1.a.a on the Thing instance cannot been done because it would throw an "cannot set a on undefined" error. That's when it goes up the prototype chain to find Entity.a which is defined and sets Entity.a.a to a new value.

[Further Edit]

As @IvoWetzel says setting thing1.b does not touch the prototype chain because setting properties does not. Where as setting thing1.a.a does two steps. A getter on thing1.a which touches the prototype chain followed by a setter of .a

Was it helpful?

Solution

A thing you could do is to apply the logic of your Entity constructor inside Thing, for example:

function Entity() {
    this.a = {a: 4};
    this.b = 5;
}
Entity.prototype.c = 6;

function Thing() {
  Entity.apply(this, arguments); // ejecutes the assignments made in Entity
}
Thing.prototype = new Entity;

var a = new Thing;
a.a.a = 3;

var b = new Thing;
console.log(a.a.a); // 3
console.log(b.a.a); // 4

console.log(a.b);   // 5
console.log(b.b);   // 5

console.log(a.c);   // 6
console.log(b.c);   // 6

OTHER TIPS

While CMS has posted a solution, why does thing2.b return 5 and why does thing2.a.a resolve to the object?

var thing1 = new Thing;

// thing1 has no a, but the prototype has so a.a is essentially the a of Entity
thing1.a.a = 3;

// Sets b on thing1, setting does not go up the prototype chain(!)
thing1.b = 4;  

// that's what thing1 looks like
Thing {proto: Entity { 
                      a: { <--- gets resolved 
                          a: 3 <-- gets set
                      }, 
                      b: 5
              },
              b: 4 <-- gets set directly
      }


var thing2 = new Thing;

// thing2.a does not exist, so we look up the prototype and find a on Entity
console.log(thing2.a.a); 

// thing2.b also does not exists, so once again we look up the prototype to find b on Entity
console.log(thing2.b);

// that's what thing2 looks like
Thing {proto: Entity {
                      a: {
                          a: 3 <- gets resolved
                      },
                      b: 5 <- gets resolved
              }
      }

All the trouble is about JavaScript going up the prototype chain in order to find properties. But when you set properties it does not go up the chain.

That's because JavaScript objects are always treated as references.

Therefore when you change the this.a object by doing a.a.a = 3; you're changing that one object in memory. New instances of Thing will reference that same object in memory because the Entity constructor is not called every time Thing is, and the this.a object remains the same.

I would put this.a outside the prototype chain, probably directly inside the Thing constructor. This would make it so that a new version of this.a is created in memory every time Thing is instantiated.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top