Вопрос

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
Это было полезно?

Решение

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";

Другие советы

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;
    },

    ...

};
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top