Question

Can anybody help me understand why the "counter" property seems to get reset on every new instance? I expected it to work like the "letters" property, which is shared across all instantiated objects.

I came across this while putting together some sample code as to why prototype properties shouldn't be used this way unless they are intended to be static.

Sample Code:

var Dog = function() {
    this.initialize.apply(this, arguments);
};
Dog.prototype = {
    counter : 2,
    letters : [ 'a', 'b', 'c' ],
    initialize : function(dogName) {
        this.dogName = dogName;
    },
    add : function(amount) {
        this.counter += amount;
    },
    arr : function(char) {
        this.letters.push(char);
    }
};

var fido = new Dog("fido");
fido.add(1);
fido.arr('d');
console.log(fido.counter); // 3, as expected
console.log(fido.letters.toString()); // ABCD, as expected

var maxx = new Dog("maxx");
maxx.add(1);
maxx.arr('e');
console.log(maxx.counter); // 3, Unexpected, Why isn't this 4?
console.log(maxx.letters.toString()); // ABCDE, as expected
Was it helpful?

Solution

This is due to the line

this.counter += amount;

What happens? this.counter doesn't find property counter on the instance, so it takes it from the prototype, but when it comes to setting, it sets it on the instance

var fido = new Dog("fido");
console.log(fido.hasOwnProperty('counter')); // false
fido.add(1);
console.log(fido.hasOwnProperty('counter')); // true

Remember it is shorthand for

this.counter = this.counter + amount;
/*    ↑              ↑
   instance          |
                 prototype */

As for letters, that is working as expected because push is happening on the Object in the prototype - you're not setting a new instance variable. If you were setting an instance variable, it may still work because Objects are assigned to variables by reference, i.e.

var a = {}, b = a;
b.foo = 'bar';
a.foo; // "bar";

OTHER TIPS

When you say this.counter += amount in add, this refers to the object that add was called on (in this case fido or maxx). In this case the += operator reads from the inherited value because there is no local value for counter and the writes to a new local value. Because fido or maxx now have their own counter properties the prototype covered up. Try the following:

Dog.prototype = {

    ...

    add : function(amount) {
        Dog.prototype.counter += amount;
    },

    ...

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