DEV Community

Asidipta
Asidipta

Posted on

Demystifying 'this' keyword in JS

Intro

This keyword holds a special place in any object-oriented programming language and has been a mind-bender in Javascript. Needless to say, it has thus been a favourite topic of interviewers everywhere.
So, let's dive into what this signifies and what its value is in different contexts.

This keyword returns the execution context of the function or code block in which this has been used.
For example, if we perform the following operations in global context (outside of any functions), irrespective of 'strict' mode or not, we will get the results as such:

const name = "XYZ";
console.log(window.name); // Prints XYZ
console.log(this === window) // Prints true
Enter fullscreen mode Exit fullscreen mode

Function Context

In this case, the value of this depends upon how the function is called.
When not in 'strict' mode:

function f() {
  console.log(this === window)
}

f(); // prints true
Enter fullscreen mode Exit fullscreen mode

In 'strict' mode, if this is not set when entering an execution context, this remains undefined:

function f() {
  'use strict';
  console.log(this===undefined);
}

f();  // prints true
Enter fullscreen mode Exit fullscreen mode

Note: You can set this using apply() or call() functions

const x = {val: 'x-val'};
const val = 'global-val';

function f() {
  console.log(this.val);
}

f() // prints 'global-val'
f.call(x) // prints 'x-val'
f.apply(x) // prints 'x-val'
Enter fullscreen mode Exit fullscreen mode

In non-strict mode, if the value of this (first argument to call() and apply()) is not an object, attempt is made to convert it into an object. 'null' or 'undefined' becomes the global object. Primitives like 1 or 'text' becomes object using respective constructors, Number and String in this example.

Class Context

The behaviour of this is similar in class and function contexts as class in javascript is just syntactical sugar. Basically, it is just a function.

Within the constructor function of a class, the this is just an ordinary object. All non-static methods of the class are added to the prototype of this object.

In derived classes, there is no this binding. One has to call super() function from the derived class. What this does is call the constructor of the base class and assign the this object from that constructor.

this = new Base()
Enter fullscreen mode Exit fullscreen mode

Note: Derived classes cannot return without calling super() or returning an object, because that will cause ReferenceError.

Bind method

ES5 introduced the bind method on functions. Calling f.bind() creates a new function with same body and scope as f. The this however is bound to the first argument passed to the bind() function. Once this is bound by using bind(), it cannot be changed.

function f() {
  console.log(this.val);
}

x = f.bind({val: 'new val'});
x(); // prints 'new val'

y = x.bind({val: 'change val'})
y(); // prints 'new val'

const obj = {val: 1, f:f, x: x, y: y};
obj.f(); // prints 1
obj.x(); // prints 'new val'
obj.y(); // prints 'new val'
Enter fullscreen mode Exit fullscreen mode

Arrow functions

In arrow functions, this retains the value of the enclosing context's this. In global context, that would mean the global object. In function context, it will be determined as like we discussed in the sections above.

For example,

const obj= {
  x: function() {
    const y = () => this;
    return y;
  }
};

// calling x with obj context and setting its reference to f
const f = obj.x();

// Calling f would normally return window or global object or //undefined in strict mode
console.log(f() === obj) // true

// However, in this case above behaviour will not be true
const f = obj.x; // we are just taking the function

// Calling f from global context
console.log(f()() === obj) // false, this will equal global
Enter fullscreen mode Exit fullscreen mode

Discussion (0)