2

I have the following code:

function Foo() {
    Foo.prototype.test = 0;
}

Foo.prototype.incTest = function() {
    Foo.prototype.test++;
};

Foo.prototype.getTest = function(name) {
    console.log(name +" this: " + this.test + " proto: " + Foo.prototype.test);
};

var bar = new Foo();
var baz = new Foo();

bar.getTest('bar');
bar.incTest();
bar.getTest('bar');

baz.incTest();
bar.getTest('bar');
baz.getTest('baz');

predictably the output is:

bar this: 0 proto: 0
bar this: 1 proto: 1 
bar this: 2 proto: 2 
baz this: 2 proto: 2 

Now I try to take advantage of this looking up the prototype chain, and change incTest to :

Foo.prototype.incTest = function() {
    this.test++;
};

This gives me completely different output!

bar this: 0 proto: 0 
bar this: 1 proto: 0 
bar this: 1 proto: 0 
baz this: 1 proto: 0

Shouldn't this.test reference the Foo prototype property? What exactly is going on here?

EDIT:

Furthermore, changing the line to Foo.prototype.test = this.test++; also produces the second output, and I'm not sure why.

EDIT 2:

Solution to first edit was postfix vs. prefix. Prefix increment produces first output.

moesef
  • 4,641
  • 16
  • 51
  • 68

2 Answers2

2

First case:

You were incrementing only the prototype variable, which will be shared by all the instances of the prototype object.

The important thing to be noted here is, when you access the test with this.test in the first case, JavaScript tries to find the test in this (current object). It fails to find it and it goes up the ladder in the prototype chain. It finds test in the Foo.prototype and returns that value. That is why you were getting same values for this.test and Foo.prototype.test.

Second case:

You were incrementing this.test. this.test++ can be understood like this

this.test = this.test + 1

Now, it fetches the value of test from the pototype chain (Foo.prototype.test will be used, which is 0), adds 1 to it and stores that result in the test member of the current object. So, you are creating a new member in this called test. That is why the value of it is different from Foo.prototype.test.

You can confirm this by adding one more method, like this

Foo.prototype.deleteTest = function () {
    delete this.test;
}

...
...
bar.deleteTest();
bar.getTest('bar');

Now bar.getTest will print 0, because we deleted the test from this, with deleteTest(). So, it will go up the ladder and find the test in Foo.prototype, which is 0.

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • I see. It didn't dawn on my that `this.test++` is equivalent to `this.test = this.test + 1`. The output makes sense if viewed this way. Thanks! – moesef Mar 28 '14 at 07:22
  • a further question. `Foo.prototype.test = (this.test++)` produces the second output... why? – moesef Mar 28 '14 at 07:28
  • @moesef because, you are incrmenting `this.test` and assigning the value before incrementing to `Foo.prototype.test`. (*Remember:* var++ is postfix operator). So, the `Food.prototype.test`'s value will be one less. Try `Foo.prototype.test = ++this.test;`, you ll be able to understand the difference :) – thefourtheye Mar 28 '14 at 07:33
  • yea. just tried that. made the difference that I was expecting. Thanks for the help! – moesef Mar 28 '14 at 07:36
-1

The this will reference the current instance of the function, not the prototype.

Evan Knowles
  • 7,426
  • 2
  • 37
  • 71
  • right. but if the current instance does not have the property `test`, shouldn't it resolve to the prototype's `test`? otherwise, `this.test` would be `undefined` and incrementing `undefined` gives `NaN` – moesef Mar 28 '14 at 07:13
  • The prototype has the property, so all of the instances inherit the property but they have their own instance. – Evan Knowles Mar 28 '14 at 07:15
  • I don't believe that is true. Otherwise the first output wouldn't happen. (ie. changing the prototype's test property value wouldn't change the object's test property) – moesef Mar 28 '14 at 07:18
  • Before the object has its own instance it automatically uses the prototype's instance. Once you set its own instance, it uses it going forwards. – Evan Knowles Mar 28 '14 at 07:23