Menu

Understanding the Keyword "this"

I have always struggled to correctly use the keyword, this, in JavaScript. This is especially the case when functions are invoked from the context of other functions. At a high level, think of this being a variable that simply refers to an object. When this is bound to an object, you can use this to set or look up properties and invoke methods on such object.

Binding Patterns for this

this can only be bound by one of five patterns, and more importantly, this is bound to an object at call time. So how do you determine which pattern was used during call time?

  1. Run the code in the debugger and pause at the line that refers to this
  2. Scan outward looking for the closest enclosing function body
  3. Once you find the function this appears in, examine the call stack and look one level down to where this function was called
  4. Identify the syntax of how the function was called to determine the run pattern

Let's take a look at each pattern.

Run Pattern Example Binding Target Purpose
Global reference this (not enclosed in any function) Global object (in a browser, it is window) Not useful, but JavaScript has to bind it to something to be consistent
Free function invocation functionName() Global object (in a browser, it is window) Not useful, but JavaScript had to bind it to something to be consistent with the other patterns
ABC (.apply, .bind, .call) fn.call(target) or obj.methodName(target) The first argument to .apply, .bid, or .call To manually pass in a this binding, like passing in arguments when invoking a function or method
Method invocation target.methodName() Object on the left of the call time dot Execute the method in the context of an object they're found on
Construction mode new functionName() A new object created for that invocation Allow a constructor to operate on the instance it is creating

Tip:

Most of the time, when inside a function, this will be bound to the object that was to the left of the call time dot.

Global Reference

console.log(this); // logs window from the browser  

Consider the above code that runs in the global scope. It is not enclosed in a function. Since this is automatically bound while inside a function body, JavaScript wanted to be consistent in having this be bound to something, so when outside a function body, this will be bound to the global context, which in the case of a browser, is window.

Free Function Invocation

var fn = function() {  
  console.log(this);
};

fn(); // logs window from the browser  

fn is being invoked in the global context. Like before, this will be bound to the global context because that is the context during run time when fn is invoked.

ABC (.apply, .bind, .call)

var fn = function() {  
  console.log(this);
};

var obj1 = {};  
var obj2 = {};

fn.apply(obj); // logs obj1

fn2 = fn.bind();  
fn2(); // logs obj2

fn.call(obj); // logs obj1  

In this scenario, when using the native apply, bind, and call Function methods, you can manually pass in an object, and this will be bound to that object. This allows you to predictively make use of this.

Method Invocation

var fn = function() {  
  console.log(this);
};

var obj1 = {mtd: fn};  
var obj2 = {mtd: obj1.mtd};  
obj1.mtd(); // logs obj1  
obj2.mtd(); // logs obj1  

Since fn is being invoked as a method whatever object is on the left of the call time dot will be bound to this. With obj2.mtd, it refers to obj1's mtd method, and invoking obj.mtd() would actually invoke fn as a method of obj1 since obj1 is to the left of the call time dot.

The phrase, call time dot, is important. Consider the following:

var obj1 = {mtd: fn};

obj1.mtd(); // logs obj1  
window.setTimeout(obj1.mtd, 1000); // logs window from the browser

/*
window.setTimeout() can be imagined like this:  
var setTimeout = function(callback, delay) {  
  wait(delay); // some logic to wait a certain amount of time
  callback();
};
*/

With setTimeout(), it takes in a function and delay (in milliseconds), and it invokes the function after the delay. In this case, since fn (the callback function that is passed as the first argument into setTimeout()) is invoked as a free function invocation, this is bound to the global context, window.

Construction Mode

var fn = function() {  
  console.log(this);
};

var obj = {mtd: fn};

obj.mtd(); // logs obj  
var obj1 = new fn(); // logs a new object  
var obj2 = new obj.mtd(); // logs a new object  

A function invoked with the new keyword means the function is considered a constructor function. This expression will create a new object that is an instance of the constructor function, and the function will execute in the context of that newly-created object.

In addition, the new keyword will override the method invocation pattern. In the example, new obj.mtd() would not bind this to obj even though obj is to the left of the call time dot. Instead, this is bound to the newly-created object from the constructor function.

Summary

I hope this helped gives clarity on how this is bound. Remember, most of the time, when inside a function, this will be bound to the object that was to the left of the call time dot.