What is `this`?

The most powerful keyword in JavaScript is this and many people get tripped by it. People expect it to work like this in Java, but understand that JavaScript is not Java. Unfortunately understanding behavior of this is little harder if you are new to JavaScript, but certainly its not a magic. And as you start getting to used to this, its rule are actually very simple.

The ‘this’ keyword evaluates to the value of the ‘ThisBinding’ of the current execution context.

The this value depends on the caller and the type of code being executed and is determined when control enters the execution context. The this value associated with an execution context is immutable. And an execution context is a specification device that is used to track the runtime evaluation of code by an ECMAScript implementation. At any point in time, there is at most one execution context that is actually executing code.

So lets understand how this works in following different contexts-

  1. Global Context
  2. Function Context
  3. Constructor Context
  4. A DOM Event Handler


1. Global Context

All JavaScript runtimes have a unique object called the global object. In browsers, the global object is the window object. When the JavaScript interpreter initially executes code, it first enters into a global execution context by default and this refers to global object which is window.

1
2
3
4
5
    var context = "global";

    console.log(" context ->        " + context);          // context -> global
    console.log(" window.context -> " + window.context);   // window.context -> global
    console.log(" this == window -> " + (this===window));  // this == window -> true

2. Function Context

Whenever you call a function the execution context changes and the new execution context depends on how you invoked the function.

  • If you invoke the function using Function.call() or Function.apply(), this will be set to the first argument passed to .call()/.apply().
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    var printContext = function() {
      console.log("context -> " + this);
    }

    printContext.call(window);    // context -> [object Window]
    printContext.call("123");     // context -> 123

    printContext.apply(window);   // context -> [object Window]
    printContext.apply("123");    // context -> 123

    //this line-
    printContext();               // context -> [object Window]

    //desugars to this -
    printContext.call(window);    // context -> [object Window]

Wait, I didn’t use .call() at line 12 then how the context is window. Basically whenever you make bare function call i.e. without .call()/.apply() as above printContext(), JavaScript will convert the call statement to printContext.call(null). If the first argument passed to .call()/.apply() is null or undefined, this will refer to window. But the catch here is if you are in strict mode then the value of this will be whatever its set to while entering into execution context, if not defined it will remain undefined.

  • If you create function using Function.bind(), this will be bound the first argument that was passed to .bind(). In this approach however you make call to the function doesn’t change value of this. Calling printContext.bind() creates a new function with same body and scope, but this is permanently bound to first argument of bind.
1
2
3
4
5
6
7
8
    var printContext = function() {
      console.log("context -> " + this);
    }

    var print = printContext.bind("bind");

    print();                // context -> bind
    print.call(123);        // context -> bind
  • If you invoke the function as a method of an object, this will refer to that object. But you can still change it to some different object using .call()/.apply().
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    var obj = {
      name: "Object",
      greet: function() {
        console.log("Hello " + this.name);
      }
    }

    obj.greet();                // Hello Object
    window.name = "window";
    obj.greet.call(window);     // Hello window

    //this line-
    obj.greet();                // Hello Object
    //desugars to this-
    obj.greet.call(obj);        // Hello Object

3. Constructor Context

When constructing a new object via new operator, JavaScript interpreter creates new empty object, set some properties on it and then call the constructor function on that new object. Thus, in this context the value this is the new object.

1
2
3
4
5
6
    var NewObject = function() {
      this.context = "NewObject";
    }

    var instance = new NewObject();
    console.log("context -> " + instance.context);      // context -> NewObject

4. A DOM Event Handler

Consider the following example, here the value of this in the function handler refers to the button you clicked on. You can observe the same in result tab.

See the Pen this in DOM Event Handler by Shridhar Deshmukh (@shree33) on CodePen.

When you click on the button, the handler is invoked as method of the button, so this refers to the target element. How that happens is here, when you say $("button").click(handler), there will be a new copy of handler created and bound to the button using .bind(). This is done by attachEvent/addEventLister method.

1
2
3
4
5
6
7
   //this is
   $("button").click(handler);

   //equivalent to
   $("button").each(function() {
     $(this).click(handler.bind(this);   // this here is particular button
   });

Summary

That’s it! If you understand and follow above rules, you will always know what this is.

Context Non Strict mode Strict mode
Global Context window window
.call()/.apply() First Argument / window First Argument / undefined
.bind() First Argument First Argument
function() window undefined
object.function() object object
Constructor Context New Object New Object
DOM Event Handler The HTML Element The HTML Element

Codepens

Comments