0

Why when I instantiate a new object in JavaScript that has another object as one of its properties, does it always reference the same object?

For example

function test() {}

test.prototype.state = {
    num: 0
};

var obj1 = new test();
var obj2 = new test();

obj1.state.num = 1;

console.log(obj1.state.num,obj2.state.num); // Outputs 1 1 instead of 1 0

Also, what would be the appropriate way to make it create a new object property every time it is instantiated?

Yoav Kadosh
  • 4,807
  • 4
  • 39
  • 56
  • That's what prototypes are for. If it was not in the prototype but in the constructor function itself as a private variable then you would get a different one each time you instantiate an object – Redu Jun 23 '16 at 15:30

3 Answers3

2

Because that's what the prototype is: a shared object among all instances. You're explicitly creating the { num: 0 } object only once, so it will exist only once. Javascript doesn't clone it for you when instantiating a new test. Usually the prototype is used for functions, where this doesn't make any difference. If you want instance specific attributes, you need to create them in the constructor function:

function test() {
    this.state = { num: 0 };
}
deceze
  • 510,633
  • 85
  • 743
  • 889
  • Interesting, I didn't know that... Is there any other way to achieve that? – Yoav Kadosh Jun 23 '16 at 15:27
  • Fundamentally: no. Of course there are many ways in which you can bend over backwards to do something more or less similar, but why would you? Instance specific attributes/values are defined in the constructor function by assigning to `this`, the `prototype` is shared among all. That's how it works. – deceze Jun 23 '16 at 15:29
0

I would like to explain in the following code.

function test() {
  var o = {a:1};
  this.geto = function(){return o.a};
  this.seto = function(v){o.a = v};
}

test.prototype.p = {a:0};

var obj1 = new test();
var obj2 = new test();

obj1.p.a = 100;
obj1.seto(50);
console.log(obj1.p.a);    // <- 100
console.log(obj2.p.a);    // <- 100
console.log(obj2.geto()); // <- 1
console.log(obj1.geto()); // <- 50

In the first code there is a closure and it is not shared. All instantiated objects have a separate closure. In the prototype version there is no closure and all instantiated objects access the very same object at the prototype of the constructor.

There is also a more complicated prototypical sharing of closures exist and that i had explained here in which we share the closure itself through the prototype.

Community
  • 1
  • 1
Redu
  • 25,060
  • 6
  • 56
  • 76
0

In your code .status.num appear to belong to the class, not instance. Change your code to something like this:

function test() {
  this.state = {num:0};//instance property
}
var obj1 = new test();
var obj2 = new test();

obj1.state.num = 1;

console.log(obj1.state.num,obj2.state.num);//1 0 as expected
Alex Kudryashev
  • 9,120
  • 3
  • 27
  • 36