1

I have a problem I can't solved because I can't explain this behaviour :

var A = function(value) {
    this.prop = value;
};

A.prototype = {
    prop: 0
};

var a = new A(1);
var b = new A(2);

console.log(a.prop);
console.log(b.prop);

output :

1
2

But, with this code (almost the same) :

var A = function(value) {
    this.prop.value = value;
};

A.prototype = {
    prop: {
        value: 0
    }
};

var a = new A(1);
var b = new A(2);

console.log(a.prop.value);
console.log(b.prop.value);

I have this output :

2
2

Can anybody explain me this ? Thanks...

EDIT :

Here's a solution :

var A = function(value) {
    this.prop = {};
    this.prop.value = value;
};

A.prototype = {

};

var a = new A(1);
var b = new A(2);

console.log(a.prop.value);
console.log(b.prop.value);
guy777
  • 222
  • 1
  • 14
  • You are mutating a shared object (mutating is when you re assign sub properties or invoke a function that changes the object). prop is shared because it's on the prototype and you don't re assign it (prop=newValue), if you would re assign it then prop would be shadowed by the instance (a and b). More on prototype and constructor functions here: http://stackoverflow.com/a/16063711/1641941 – HMR Dec 10 '13 at 10:27

4 Answers4

1

prototype is created only once and it's only a simple object whose childs are attached for all instances of a function it belongs to.

So it's basically the same as if you write:

var obj = { value: 0 };

var a = {}, b = {};

a.obj = obj;
b.obj = obj;

obj.value = 2;

as you can see both a.obj and b.obj references to the same obj and both a.obj.value and b.obj.value will be 2 in this example

Adassko
  • 5,201
  • 20
  • 37
1

Think of a prototype property as a property shared amongst all instances.
Yet you can override it on each instance, that 's what you do in the first example.
Once overriden in each instance, you do not access any more to the prototype property with obj.prop, which now refers to the instance property. You would need to use obj.prototype.prop to read it again, but this syntax is illegal : you can use obj.__proto__.prop (non standard) or Object.getPrototypeOf(obj).prop (EcmaScript 5) to do so.
In the second instance, you do not change the property in the constructor : rather you change a property of this property. So both constructor access to the very same object, then change one of its property value, so the last to set it will 'win'. Here the prototype property is not overriden ('hidden') by the instance property and accessing obj.prop in fact access 'obj.prototype.prop'.

GameAlchemist
  • 18,995
  • 7
  • 36
  • 59
1

This is happening because in JS, objects are passed by reference, while primitives are not.

Since the prototype is shared between the 2 instances, modifying a object on it will update all instances.

Andrei Rosca
  • 1,097
  • 13
  • 27
1

In example 1, this.prop is a primitive type, which is referenced by value and thus not shared between instances.

In example 2, this.prop is an Object whose reference is initialized from the prototype from a single object, so this single object is shared by all instances.

In the last "example" solution, you create a new object with = {}, so all instances now have their own object.

More details about primitive types : Primitive value vs Reference value

Community
  • 1
  • 1
Offirmo
  • 18,962
  • 12
  • 76
  • 97
  • To be more correct: it doesn't matter if A.prototype.prop is primitive or object. When assigning it in the constructor with this.prop the prop value will be shadowed. The second example doesn't re assign it but mutates it. Since primitive can't be mutated the only way to change them is to re assign and thereby shadow it. In example 1 the prop value is also shared as the following answer demonstrates: http://stackoverflow.com/a/16063711/1641941 – HMR Dec 10 '13 at 12:28