DEV Community

Allen Shin
Allen Shin

Posted on

Understanding Execution Context Part 2: Get "this"

In my last post, I went over some introductory concepts regarding the execution context in Javascript, how it's created, and how variables behave in differing execution contexts. To give a brief recap, in Javascript, there are two main phases in which the code runs. The first is called the creation phase, in which Javascript allocates memory space for all of the variables, objects and functions, that exist in a given execution context. The first relevant execution context for any piece of code is the global context. After allocation of the necessary memory space during our creation phase, the second phase is called the execution phase. This is the part where our code is run line-by-line, and where our code begins to take shape. You can define your variables, use variables in statements, and you can even run functions and create new executions contexts. When you run functions, you do this whole process all over again.

Today, I want to go over something specific which was another concept that was mysterious to me, which is the 'this' object. Now, we know that this is created during the creation phase along with the global object (the object, where all the variables in that execution context are stored), and the outside environment(the object, where all the variables outside that execution context are stored).

Before we get into a more general discussion, I first want to cover the context which I first learned about the 'this' object: class functions. When you write a class declaration function, you typically use 'this' in the function like so

class Rectangle {
  constructor(height, width){
    this.width = width,
    this.length = length
  }
}
Enter fullscreen mode Exit fullscreen mode

... with which you could create new instances of the class, by calling the function like so

  var square = new Rectangle(5, 5)
Enter fullscreen mode Exit fullscreen mode

What this simple example demonstrates, is that the instances are all objects that are being created by this class function. The class function is actually just syntactical sugar for the prototypical inheritance that already exists in Javascript. So essentially, this is referring to the object that is created through the prototypical 'class' method. The example shows us that the variable width is an attribute of 'this', that which is in reference to the specific rectangle object instance that is created through the class method. To clarify this point further, let's take a look at an example given from the MDN page on 'this'.

var o = {f: function() { return this.a + this.b; }};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5
Enter fullscreen mode Exit fullscreen mode

We can see here that the object is created with the name variable o, with a function inside of the object referencing 'this'. The way that the 'this' is utilized is in reference to the specific instance which is created, here defined with the variable p.

Now when I first learned about all this, I knew that 'this' was in reference to the instance in a class method, but I was confused about what this meant in a typical setting without class methods. Now if we recall functions and variables are created during the global context's creation phase, with the variables and functions given key value pairs on the object. Any method that gets created in the global window, is in reference then to the "instance" of the window object. This was a bit confusing for me to grasp at first. But you can clearly see, when you run this function on your browser's console...

var a = function(){
  console.log(this)
}
a() 
Enter fullscreen mode Exit fullscreen mode

... you get back the result of your window object, which is ultimately just an object, just like all those instances of class methods.

How then can you get something besides the window object as your reference? Well, just like you had all those methods with 'this' inside the instance object, you can create an object that has a method inside of it, with this. When you console log something like this...

var outerObject = {
    log: function(){
      console.log(this)
    }
  }
  console.log(outerObject.log())
Enter fullscreen mode Exit fullscreen mode

... You weill get back the object in which this method lies on. Again, the 'this' is referring to the object with which the method it lies in refers to.

One thing that is worth noting, which is specific to Javascript is that there is something which many JS programmers consider a bit of a bug. Let's say we create a function inside of the function which is referring to the outerObject variable in our previous example, and within that function, we reference this once again.
Something like this.

var outerObject = {
    log: function(){
      console.log(this)
      var innerFunction = function(){
        console.log(this)
      }
      innerFunction()
    }
  }
  console.log(outerObject.log())
Enter fullscreen mode Exit fullscreen mode

We should expect that both times 'this' is console logged, we should get back the same object reference, right? Well, if you ran this yourself, you'll be surprised to see that the second 'this' equals the window object. I have no idea why JS programmers made it like this, but my guess(and approach to remembering this) is that the innerFunction execution context isn't run with an object to reference. It's just run with the command innerFunction()(unlike the outerObject.log()), and that causes the 'this' in the innerFunction to default back to the window.

There is a way to bypass this default setting. Since 'this' in the initial context of the first function we know is referring to the outerObject variable, we can set that 'this' to a variable in order to save it in memory space. Doing this helps reduce the confusion when 'this' ends up changin with different execution contexts.

var outerObject = {
    log: function(){
      var self = this
      console.log(self)
      var innerFunction = function(){
        console.log(self)
      }
      innerFunction()
    }
  }
  console.log(outerObject.log())
Enter fullscreen mode Exit fullscreen mode

We set the 'this' to a self variable, and now that's locked in memory, so when we call on it again in the innerFunction's context, we get the same object reference as the first 'this'.

With that, I'll leave MDN's definition here for 'this' to help solidify our understanding.

A property of an execution context (global, function or eval) that, in non–strict mode, is always a reference to an object and in strict mode can be any value

We didn't cover strict mode, but that will be for next time. ;)

Top comments (0)