Where should I declare an instance variable in Javascript?

Asked

Viewed 1,221 times

12

I’m having doubts about creating instance variables in a Javascript constructor class/function. I have read in several places that the declaration of an instance variable is made within the class body as in the example below:

function Spam() {
    this.foo = "foo"
}

But I realized I can also declare the variable in prototype class as in the example below:

Spam.prototype.bar = "bar";

And in the end I end up getting the same result:

var mySpam = new Spam();
mySpam.foo    // => "foo": declarado no corpo da classe
mySpam.bar    // => "bar": declarado no prototype da classe

What is the difference between the two methods of declaring an instance variable?

2 answers

10


foo is a variable only of the object you prompted, while bar is the prototype of the objects Spam (all objects).

The difference is that in the first case each object has its own variable, while in the second all objects of that prototype divide the same variable.

var mySpam2 = new Spam();

console.log(mySpam.bar); // "bar"
console.log(mySpam2.bar); // "bar"

Spam.prototype.bar = "qux";

console.log(mySpam.bar); // "qux"
console.log(mySpam2.bar); // "qux"

Note that by changing the value of bar of the prototype this affected the access of that property in all objects Spam. With the property foo the same is not possible, since it is property of the object and not of the prototype.


Be careful not to hide the prototype unintentionally

The correct way to change the value of the prototype is as I did in the example:

Spam.prototype.bar = "qux";

Note that we are explicitly changing the prototype. Beware that the following, contrary to what may seem, nay is equivalent:

mySpam2.bar = "baz";

In that case we didn’t change the prototype, we create a new property only on the object mySpam2 whose name is the same as that used in the prototype ("hiding" the prototype on that object).

  • Is there a problem with "hiding the prototype"? As far as I know, the principle behind prototypic inheritance (as opposed to classical inheritance) is precisely to take an existing object, well characterized, and state "that other object looks like that, the differences are x, y and z". (although I recognize that in practice this is not always used this way)

  • 1

    @mgibsonbr, no, no problem (Duck Typing is for that same). I only stressed in the answer because, for those who come from another language (ex: Static in Java or C#), it may not be so obvious the difference.

  • Just clarifying in case someone gets confused, in mySpam2.bar = "baz"; what will be hidden is not the entire prototype of the object, but only the property bar.

4

The difference is that the variable declared in prototype is shared between all instances of the class. If it has a simple value, it does not matter, but if it is a complex variable (a list, or an object) then modifying its components will have side effects on the other objects in the class:

function Spam() {
    this.a = 10;
    this.b = [1,2,3];
}
Spam.prototype.c = 10;
Spam.prototype.d = [1,2,3];
Spam.prototype.print = function() {
    console.log(JSON.stringify({a:this.a, b:this.b, c:this.c, d:this.d}));
}

var s1 = new Spam();
var s2 = new Spam();

s1.print();
s2.print();

s1.a = 20;
s1.b[1] = 4;
s1.c = 20;
s1.d[1] = 4;

s1.print();
s2.print();

Upshot:

{"a":10,"b":[1,2,3],"c":10,"d":[1,2,3]}
{"a":10,"b":[1,2,3],"c":10,"d":[1,2,3]}

{"a":20,"b":[1,4,3],"c":20,"d":[1,4,3]}
{"a":10,"b":[1,2,3],"c":10,"d":[1,4,3]} 

Notice that when you did s1.c = 20 he nay assigned Spam.prototype.c, and yes s1.c, so there was no side effect. But when you leu s1.d and then modified one of its components (the second index), so you ended up changing the shared object.

So that - answering your question - the correct place to assign any instance variable mutable is within the class body (constructor).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.