So I've seen and heard that the methods should be set in the constructor's prototype property so it doesn't have several different instances. But what about properties themselves? Which is best practice? If that's the case, shouldn't constructor's always be empty?
function Gadget(name, color) {
this.name = name;
this.color = color;
this.whatAreYou = function(){
return 'I am a ' + this.color + ' ' + this.name;
}
}
should this actually be...?
function Gadget(name,color){}
Gadget.prototype.name = name;
Gadget.prototype.color = color;
Gadget.prototype.whatAreYou = function() {
return 'I am a ' + this.color + ' ' + this.name;
};
If you set it on the prototype, the property is shared by all instances. Not usually what you want. I I blogged about this at http://js-bits.blogspot.com/2014/10/understanding-prototypical-inheritance.html . You usually want each Gadget to have their own name and color. How would you do that with the code you suggested?
By the way, the code you suggested has undefined variables (name, color)
The normal way is to set methods on the prototype, and regular values on the object itself. Unless you do want a property to be shared by all instances, that's like what we would call static properties in static typed languages.
Here's an example
function Gadget(name,color){
this.name = name;
this.color = color;
// Since all gadgets in on the prototype, this is shared by all instances;
// It would more typically be attached to Gadget.allGadgets instead of the prototype
this.allGadgets.push(this);
// Note that the following would create a new array on the object itself
// not the prototype
// this.allGadgets = [];
}
Gadget.prototype.allGadgets = [];
Gadget.prototype.whatAreYou = function() {
return 'I am a ' + this.color + ' ' + this.name;
};
An important concept to remember is that writes (assignments) are always applied to the object itself, not the prototype. Reads, however, will traverse up the prototype chain looking for that property.
That is
function Obj() {
this.map = {};
}
function SharedObj() {}
SharedObj.prototype.map = {};
var obj1 = new Obj();
var obj2 = new Obj();
var shared1 = new SharedObj();
var shared2 = new SharedObj();
obj1.map.newProp = 5;
obj2.map.newProp = 10;
console.log(obj1.map.newProp, obj2.map.newProp); // 5, 10
// Here you're modifying the same map
shared1.map.newProp = 5;
shared2.map.newProp = 10;
console.log(shared1.map.newProp, shared2.map.newProp); // 10, 10
// Here you're creating a new map and because you've written to the object directly
// You don't have access to the shared map on the prototype anymore
shared1.map = {};
shared2.map = {};
shared1.map.newProp = 5;
shared1.map.newProp = 10;
console.log(shared1.map.newProp, shared2.map.newProp); // 5, 10
For properties this may not behave the way you expect it to. Methods should be declared as on the prototype, because you want all instances to share the same function reference. Properties are usually different per instance. You might not notice this when dealing with primitives, but you will experience "weird" behavior for properties that are objects (or arrays, …)
function Test(){}
Test.prototype.foo = {bar: 1};
Test.prototype.baz = 1;
var one = new Test();
var two = new Test();
one.foo.bar = 3;
two.foo.bar === 3; // true, because of object reference
// BUT:
one.baz = 3;
two.baz === 1; // true
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With