~ read.

Understanding 'this' in Javascript

The mysterious this makes many an appearance in our code. But what is this really? We may know how to use it, we may be completely clueless, either way let's break it down a little bit.

In Javascript, this refers to an object, specifically the object that is executing the code.

For example:

   var Dog = {

       name: "Spot",

       breed:"Yorkshire Terrier",

       description: function(){
       //we could write our function using this           
      console.log( "My name is " + this.name + 
      "and I am a " + this.breed );

      //we could write our function using dog
      console.log( "My name is " + dog.name + 
      "and I am a " + dog.breed );

   } 

When I think about this, I think about context.

We see that we can use the object name, or this, and refer to the same context as dog. Why use this? Well, because when we use this we know it is bound to the object's scope it is called in — put another way, it lets us be sure that we know that the object we're trying to access is indeed the one we are calling this in. Why would that not be the case when we use dog? Well, we could have a global variable named dog already, and attempting to access dog.name might give us the dog global variable instead of the local dog that we want.

Ok, so now we know that this can be useful, but how do we use it? And how do we know exactly what this refers to?

Definition

this is a binding that gets defined according to the context in which it is called, it refers to the object that is set by the call site of the function. The value of the object is set by four rules (in decreasing precedence): new binding, explicit binding, implicit binding, and default binding

What did I just read? Ok, it might sound like meaningless words, but re-read it a few times, read on, and I promise it will click.

1. New Binding

New Binding is when — you guessed it — the new keyword is used in a function call.

var spotClone = new Dog()

When the new keyword is used, four things happen.

1)A new object is created, this is set equal to that object.
2)Whatever you called new on, has its __proto set to the prototype of Dog, and so any function on the prototype is available to the newly returned this object.
3)The Dog constructor is run
4)The this object is returned, which here gets returned to spotClone.

If that felt confusing, don't worry, it takes some practice writing classes and using javascript. If you find yourself confused about what this is referring to when out in the wild west of coding, go back to this post.

If new is not used, then the next binding that takes precedence is explicit binding. Read on!

2. Explicit Binding

When you use call, apply, or bind functions, the context this gets set accordingly (check here if you want to learn more about these functions).

If an explicit binding is not used, then an implicit binding takes precedence.

3. Implicit Binding

This is whatever called the method, I like to think of it as whatever is to the left of the function call (if you do spotClone.description(), then this inside description refers to spotClone)

4. Default Binding

If we have none of these, then we default to the global object, which is different depending on your runtime environment. In the browser, the global object is window. In Node.js it's global. There's actually a good reason for why this happens — in the global scope, all global variables and functions are defined on the global object. So this is just getting the invoking object once again.

OK, so when you think this, think context! And to figure out the context, think which of the four rules applies.

Note: inside a closure, you can't refer to the outer function's this, because it is only accessible to the outer function. Instead, this gets bound to the global window object (when strict mode is not being used).

 var DogTypes = {

   numBreeds = 3;

   breeds:[{'name': "Yorkshire Terrier"}, {'name'    : "Hound"}, {'name' : "Golden Retriever"}]

   description: function(){
      this.breeds.forEach(function(dog){
      //inside here we can't access the outer 
      //function's "this"
       console.log(this.numBreeds) // undefined!
      })
    }

 }

To solve this problem, we often use call, apply, or bind methods, or we can set another variable to *this *outside of the closure, and reference it in the inner function. Sometimes you'll see something like var that = this

It's pretty magical when you start using this and feeling good about it. I promise you'll get there too!

comments powered by Disqus