In the past when creating "classes" in JavaScript, I have done it like this:
function Dog(name){
this.name=name;
this.sound = function(){
return "Wuf";
};
}
However, I just saw someone do it like this instead:
var Dog = (function () {
function Dog(name) {
this.name = name;
}
Dog.prototype.sound = function () {
return "Wuf";
};
return Dog;
})();
Can you do it both ways, or is the way I've done it wrong? In that case, why? And what exactly is the difference between the two in terms of what we end up with? In both cases we can create an object by saying:
var fido = new Dog("Fido");
fido.sound();
I hope someone will enlighten me.
In the past when creating "classes" in JavaScript, I have done it like this:
function Dog(name){
this.name=name;
this.sound = function(){
return "Wuf";
};
}
However, I just saw someone do it like this instead:
var Dog = (function () {
function Dog(name) {
this.name = name;
}
Dog.prototype.sound = function () {
return "Wuf";
};
return Dog;
})();
Can you do it both ways, or is the way I've done it wrong? In that case, why? And what exactly is the difference between the two in terms of what we end up with? In both cases we can create an object by saying:
var fido = new Dog("Fido");
fido.sound();
I hope someone will enlighten me.
Share Improve this question asked Mar 24, 2015 at 13:49 MBrownMBrown 5931 gold badge4 silver badges14 bronze badges 1- More on how to use constructor functions and prototype can be found here: stackoverflow./a/16063711/1641941 hope it helps – HMR Commented Mar 24, 2015 at 23:38
4 Answers
Reset to default 15There are two important differences between your way and theirs.
- Wrapping in a self invoking function (
(function() { ... })();
) - Using the
.prototype
property overthis.
for methods.
Wrapping things in a self invoking function, then assigning the result (as defined in the return
statement to a variable is called the module pattern. It's a mon pattern to ensure scope is more controlled.
Using Dog.prototype.sound = function() {}
is preferable to this.sound = function()
. The difference is that Dog.prototype.sound
is defined once for all objects with the Dog
constructor, and the this.sound = function() {}
is defined again for each Dog object created.
The rule of thumb is: Things that are individual to an object (usually its properties) are to be defined on this
, while things that are shared to all objects of the same type (usually functions) are to be defined on the prototype.
With your code, you're creating a new function sound
for every new Dog
instance that's being created. Javascript's prototype
avoids this by creating only a single function which all object instances share; basically classical inheritance.
In the second code you're showing that's just additionally wrapped in an IIFE, which doesn't do much in this case.
The first is the traditional method of creating a constructor. The second an immediately invoked function expression that returns a constructor. This method allows you to keep variables within the module without leaking out into the global scope which could be an issue.
And what exactly is the difference between the two in terms of what we end up with?
They both, as you've seen, have the same result. The others have talked about prototype
so I won't mention it here.
The second is preferable because it takes advantage of Javascript's prototypal inheritance mechanism.
Prototypes
Javascript inheritance is a cause of confusion, but it's actually fairly simple: every object has a prototype, which is an object that we will check when we try to access a property not on the original object. The prototype will, itself, have a prototype; in a simple case, like Dog
, this will probably be Object.prototype
.
In both of your examples, because of how the new
operator works, we will end up with a prototype chain that looks like this: fido->Dog.prototype->Object.prototype
. So, if we try to look for the name
property on Fido, we'll find it right there on the object. If, on the other hand, we look for the hasOwnProperty
property, we'll fail to find it on Fido, fail to find it on Dog.prototype
, and then reach Object.prototype
, where we'll find it.
In the case of sound
, your examples define it in two different places: in the first case, fido
and every other dog we create will have their own copy of the function. In the second case, Dog.prototype
will have a single copy of the function, which will be accessed by individual dogs when the method is called. This avoids wasting resources on storing duplicates of the sound
function.
It also means that we can extend the prototype chain; maybe we want a Corgi
class that inherits the sound
function from Dog
. In the second case, we can simply ensure that Dog.prototype
is in Corgi.prototype
's prototype chain; in the first, we would need to create an actual Dog and put it in the prototype chain.