Alright Agent Kay, I'll approach this question in a different way than Esailija did. Let's begin with simple objects. For example say you already have an object called gandalf
:
var gandalf = {
color: "grey",
comeBack: function () {
this.color = "white";
return this;
}
};
There are no constructors in this code. Hence this code is easy to understand. Am I right or am I right?
Alright, now I'm going to do something awesome. I'll create radagast
from gandalf
:
var radagast = Object.create(gandalf);
radagast.color = "brown";
What's happening here? Let's break it up:
- We create a new object called
radagast
from gandalf
using Object.create
. Hence radagast
inherits from gandalf
.
- We set the
color
of radagast
to brown instead of grey.
To make it even more simple imagine you and I had the following conversation:
I: Hey Agent Kay, I met Radagast yesterday.
U: Who's Radagast?
I: Hmm... do you know who's Gandalf?
U: Yes, I do.
I: Well Radagast is just like Gandalf except that he's brown instead of white.
This is exactly how inheritance works in JavaScript. You see JavaScript has prototypal inheritance. In prototypal inheritance objects inherits from other objects. In this case radagast
inherited from gandalf
.
Now they way prototypal inheritance is usually implemented in JavaScript is weird. I call it the constructor pattern of prototypal inheritance. For example, take your code:
function Gandalf() {
this.color = "grey";
}
Gandalf.prototype.comeBack = function() {
this.color = "white";
return this;
};
Now when you create an instance of Gandalf
what object does the instance inherit from? It inherits from Gandalf.prototype
:
var gandalf = new Gandalf;
alert(Object.getPrototypeOf(gandalf) === Gandalf.prototype); // true
What's happening when you say new Gandalf
is:
var gandalf = Object.create(Gandalf.prototype);
Gandalf.call(gandalf);
If you expand Gandalf.call(gandalf)
the you get:
var gandalf = Object.create(Gandalf.prototype);
gandalf.color = "grey";
Now take your second example:
function Gandalf() {
this.color = "grey";
this.comeBack = function() {
this.color = "white";
return this;
};
}
In this case when you create an instance of Gandalf
you're essentially doing this:
var gandalf = Object.create(Gandalf.prototype);
gandalf.color = "grey";
gandalf.comeBack = function () {
this.color = "white";
return this;
};
Hence every time you create a new Gandalf
you create a new function comeBack
. Thus if you call new Gandalf
10 times you'll have 10 different comeBack
functions as well.
Compared to this in the first example since comeBack
is defined on Gandalf.prototype
, every time we call new Gandalf
we get a new object which inherits from Gandalf.prototype
. Hence there's only one comeBack
function which is shared amongst all instances of Gandalf
. Isn't that better?
Essentially think of your first example like this:
var gandalfPrototype = {
create: function () {
var gandalf = Object.create(this);
gandalf.color = "grey";
return gandalf;
},
comeBack: function () {
this.color = "white";
return this;
}
};
var gandalf = gandalfPrototype.create(); // there's only one comeBack function
Similarly your second example is equivalent to this:
var gandalfPrototype = {
create: function () {
var gandalf = Object.create(this);
gandalf.color = "grey";
gandalf.comeBack = function () {
this.color = "white";
return this;
};
return gandalf;
}
};
var gandalf = gandalfPrototype.create(); // there's 1 comeBack for each instance
Remember that when you use new
before a function call you're actually inheriting from the prototype
of the function. Not the function itself.
Finally I would like to say (because I'm a big fan of J.R.R. Tolkien) that this is the way I would write your code:
var wizard = {
create: function (color) {
var wizard = Object.create(this);
wizard.color = color;
return wizard;
}
};
var gandalf = wizard.create("grey");
gandalf.comeBack = function () {
this.color = "white";
return this;
};
var saruman = wizard.create("white");
var radagast = wizard.create("brown");
Thank you for reading my answer.