For me, some of the most confusing things as a new JavaScript developer were the keywords this
, new
, and prototype
. Being someone who started with the strongly object oriented language Java (no relation) only made my confusion worse: “I use new
to create a new instance of a class? Sounds familiar. But wait, why am I adding methods to a prototype
? Seems a bit roundabout. And what exactly is this
referring to again???” I was learning what to do by rote, which made mistakes common, trips to google frequent, and coding miserable.
Until last week.
Last week Hack Reactor dropped a bombshell of lesson on me. The mists parted, and three of the most confusing keywords in JavaScript suddenly made sense. It all starts with classes. You see, while some languages are built from the ground up to support object-oriented tools, JavaScript is not one of those languages. So the ways you can build a class are a little more . . . improvised.
Functional Style Classes
Functional classes are perhaps the most straightforward of the bunch. You want a thing, you make the thing, you return the thing. Our code here allows us to create as many dudes as we like, and we know they’ll all have a name, two thumbs, and a greeting function. It’s easy to follow the code, easy to write the code, and we don’t need to use any weird words.
But, what if we need to make thousands of dudes? Suddenly that greeting function, which is identical for each dude, is starting to hog a lot of memory, needlessly getting remade over and over again. Wouldn’t it be nice if there were a way all the dudes could share one greeting?
Functional-Shared Classes
Simple! Easy. We’ve made a separate object dudeMethods
to hold all of methods we might want to assign to dudes. And even if we end up with hundreds, we can assign them all in one line of code (if we have (Underscore.js)[http://underscorejs.org] installed) with _extend(dude, dudeMethods);
. Now our dudes are all using the same greeting, we’re saving a ton of memory, and still no weird words. Awesome!
Well . . . no, not quite. Unfortunately the above code is broken and will behave in unexpected ways. There is one big step we missed. Now that greeting
is being defined outside of makeDude
, the variables dude.thumbs
and dude.name
no longer have any meaning. dude
is defined elsewhere, and there is no way for dudeMethods.greeting
to have any idea what they are.
That’s where this
comes in. It seems like dark magic, but think of this
as just another parameter. Just like makeDudes
gets a name
parameter, greeting
function can have a this
parameter. The only difference: we pass it in with dot notation. When we call bob.greeting()
later, bob
will be set to this
. So if we rewrite our greeting function slightly…
The keyword this
gets thrown around a lot in JavaScript, with big words like “runtime context”, but just think of it as a parameter, and your life will be much easier. The big exception is when you try to use this
in a function that was called without any object to the left of the dot. In that case, it just ends up pointing to the “global scope” (usually the browser window), which is a useless and kind of confusing feature. But hey. JavaScript.
Prototypal Style Classes
The Prototypal method of creating classes in JavaScript, despite its name, does not use the keyword prototype
at all. In fact, it’s not much different from Functional-Shared. We still have dudeMethods
holding our functions, we’re just taking advantage of Object.create
’s ability to make a new copy of an object to save a step or two. Since our dudes start out as copies of dudeMethods
, there’s no need to explicitly assign those methods anymore.
Easy enough, but whatever happened to new
and prototype
?
Pseudoclassical Style Classes
“What in heaven’s name is this now?!? Where did all of the code go? If this
is an object calling a function shouldn’t it refer the browser window here? What the heck are new
and prototype
doing anyway???” Believe it or not, this code is actually very similar to the Prototypal class from before.
The big thing to understand is that the keywords new
and prototype
are conveniences ginned up in order to save developers from writing a bit of code. Nothing particularly new is happening under the hood. For example, prototype
is nothing more than an object automatically created by JavaScript and attached to every function (remember that in JavaScript, functions are themselves objects, which means that they can have their own properties). Dude.prototype
is very similar to dudeMethods
from before, the big difference being we didn’t have to build it ourselves.
What about new
? Well, that one is a little stranger, but still not so different from what we’ve seen before. By calling a function with the new
keyword, we call it in “constructor mode”, which means nothing more than that JavaScript will automatically insert two lines of code for us: one to set this
to a newly created copy of the function’s prototype
, and one to return this
. In other words, when we actually run new Dude()
above, the code it will look like more like this:
Almost identical to our Prototypal class from before! We can clearly see why this
doesn’t refer to the browser window. The very first line of the code now explicitly sets this
to be something else. JavaScript could have used “obj”, “instance”, or anything else to store the copy of prototype
, but the designers chose this
. It was already a reserved word and would otherwise serve little purpose inside a constructor function like Dude
. A decision that would later confuse thousands of new developers like me, and possibly you.
TL;DR
- JavaScript was not built with classes in mind, and so has had to hack together different, sometimes odd, ways of creating them.
- The keyword
this
is basically just another parameter for your functions, and will always refer to the object that called the function (i.e. for “obj.func()”, obj isthis
).- Unless, of course,
this
is explicitly overridden, such as by the keywordnew
or by the ‘call’, ‘apply’, and ‘bind’ methods.- Or if the function wasn’t called by an object at all, because then
this
will refer to global scope (i.e. the window), because reasons.- A
prototype
is just an object which is automatically generated as a property of every function. It’s used to store methods we would like every “instance” of the function to have (and for inheritance, but don’t worry about that for now).- The keyword
new
calls your function in “constructor mode”, automatically inserting two lines of code. One at the beginning which setsthis
to be a copy of theprototype
, and one at the end which returnsthis
.