Ray
Ray

Reputation: 41

Javascript functions' prototype is shared between objects??

All the resources I have found, it says that if we use Javascript prototype pattern, that functions' prototype is shared between all the objects for that particular type. that means the following;

function TestObj(){
}

TestObj.prototype = {
    cVar: 15,
    increase: function(){
        this.cVar++;
    }
};

var a = new TestObj();
var b = new TestObj();
a.increase();
console.log(a.cVar); // 16
console.log(b.cVar); // 15 ??

Now my question is, shouldn't the b.cVar be 16? why is it 15 then? And if it is 15 that means the TestObj with protype is not shared between objects.

Do you know??

Upvotes: 3

Views: 476

Answers (4)

go-oleg
go-oleg

Reputation: 19480

Yes, an object's prototype is shared between instances of the object, but the this.cVar++ looks a little bit misleading.

I think its easier to explain if you rewrite

this.cVar++;

as

this.cVar = this.cVar + 1;

The important thing is that this refers to the object instance and not the prototype. So in this.cVar + 1 it'll check the object instance to see if it has a cVar property. The first time increase is called, it doesn't. So JavaScript will look up the prototype chain until it finds it. So it finds 15. However, when it does the actual assignment back to this.cVar, it sets the property on the object instance itself and not the prototype (a shadowing of sorts).

So in your example,

console.log(a.cVar); // returns property from `a` itself
console.log(b.cVar); // returns property from the prototype

We can show this by using hasOwnProperty:

console.log( a.hasOwnProperty( "cVar" ) ); // true
console.log( b.hasOwnProperty( "cVar" ) ); // false

Upvotes: 6

Matthew Cox
Matthew Cox

Reputation: 13672

Objects do, in fact, share the prototype with one another as your research has lead you to believe. However, as go-oleg eluded to, there is a concept of the prototype chain. The prototype chain has a couple of behaviors you have to understand.

When you try to access a property on an object, it recursively looks up the chain starting from the object and looks for the property, then returns the value (This is what happens in the case of a read/get action).

When you try to set the value on a property on an object, it doesn't bother to recurse up the chain to find the property in the chain. Instead, if it doesn't find one on the object, it just adds the property along with the value you set on the object itself. This effectively hides the property that is higher up the prototype chain (This is what happens in the case of a write/set action).

If you placed your value inside an object then tried to set the value however, it would recurse to the object reference in a read attempt and since you have a reference pointer to the object, you would be setting the value on the object directly which would have the outcome you were expecting:

function TestObj(){
}

TestObj.prototype = {
    cVar: 15,
    obj: { val: 5 },
    increase: function(){
        this.cVar++;
    },
    objInc: function() { 
        this.obj.val++;
    }
};

var a = new TestObj();
var b = new TestObj();
a.increase();
console.log(a.cVar);
console.log(b.cVar);

b.objInc();
console.log(a.obj.val);
console.log(b.obj.val);

//output
//16
//15
//6
//6

Hopefully that distinction clears up the confusion.

Upvotes: 3

Jonny Henly
Jonny Henly

Reputation: 4223

Your getting confused by the terminology, and TestObject a is the only TestObject that you call increase() on. So it makes sense that a = 16 and b = 16, since you never call b.increase().

... that functions' prototype is shared between all the objects for that particular type.

That doesn't mean that each time any TestObject calls increase() then every other TestObject and itself also increase their cVar. Your thinking of something similar to the way that an EventListener and EventDispatcher system is set up. That function's prototype shared between all the objects for that particular type means that each TestObject instance has the prototype you defined.

Upvotes: 0

J148
J148

Reputation: 576

To be clear, "a" is an object, "b" is another, separate, object. You then call the increase function only on "a", not "b". Therefore, unless I'm off my rocker, It would make sense that b.cVar = 15, since it was never incremented.

Upvotes: 0

Related Questions