this

Whenever we invoke any function in JavaScript, a brand new execution context is created at the run-time and an object is created which is referred to as this.

this refers to the current function execution context 1 and its value inside a function depends on the style of function invocation.

The value of this depends on how the function is called and is evaluated during the run-time.

It is a very important and confusing concept. A lot of questions can be asked, which can be answered correctly only if you know the concept very well.

For example -

For the same method, value returned is different in both cases because value of this depends on how the function/method is invoked and not on where it is declared

1
2
3
4
5
6
7
8
9
10
11
12
var a = 2;
var obj = {
  a: 33,
  foo: function() {
    return this.a;
  }
}

console.log(obj.foo());   // 33

var bar = obj.foo;
console.log(bar());   // 2

We need to check that how the function is invoked, and based on that, we need to apply one of the four rules to find out the value of this inside any function -

With the introduction of ES6, the value of this is now also dependent on the way a function is created -

  • Function type - arrow functions or normal functions
  • Classes - non-static method or static method

Now, let us look at those rules in detail with the help of examples.

Rule 1: Standalone function invocation

It is the most common way of invoking a function.

According to this rule, if the function gets invoked without any object reference or any other bindings. The value of this will be equal to -

  • window in non-strict mode
  • undefined in strict mode

non-strict mode

Here, we have created a function foo and, when we invoke that in the non-strict mode, this resolves to the global object.

1
2
3
4
5
function foo() {
    console.log(this);  // [window]
}

foo();

Similarly, If declare a variable var a = 2;, in the global scope, it is same as adding a variable a inside a global scope. So, when we invoke foo in this case it prints 2 which was assigned to var a.

1
2
3
4
5
6
7
function foo() {
    console.log(this.a);  // 2
    console.log(window.a);  // 2, [because, this = window]
}
var a = 2;

foo();

In these examples, Rule 1 is applied because we are calling foo() without any bindings, and also, nothing is present on the left side of the foo() call.

strict mode

If we try to execute the same code in strict mode, we will always get this as undefined.

1
2
3
4
5
6
7
8
'use strict';
function foo() {
    console.log(this);  // undefined [because, this !== window]
    console.log(window.a);  // 2, [because, `a` is created on global window object]
}
var a = 2;

foo();

Rule 2: Invoked as an object method

If we invoke a function as a method(function defined inside an object is known as method), then the value of this inside a method is always equal to the current object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var myObj = {
    a: 2,
    // foo is declared as a method
    foo: function() {
        // returning the current value of `this`
        return this;
    }
}

// Way 1
console.log(myObj.foo());     // myObj{} -> {a: 2, foo: [f]}
console.log(myObj.foo() === myObj);     // true
console.log(myObj.foo().a);   // 2

// Way 2
// We can also store the object into a variable
// returned by invoking the method 
var bar = myObj.foo();
console.log(bar);   // myObj{} -> {a: 2, foo: [f]}
console.log(bar === myObj);     // true
console.log(bar.a);     // 2 

This is how the invocation of an object method works, but in interviews this question can be asked differently, as shown in the example below -

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Way 3
var myObj = {
    a: 2,
    // foo is declared as a method
    foo: function() {
        // returning the current value of `this`
        return this;
    }
}

var bar = myObj.foo;
// invoked as a standalone function(Rule 1)
console.log(bar());   // [window(non-strict mode), undefined(strict mode)]
console.log(bar === myObj);     // false
console.log(bar.a);     // undefined

Everything is same as that of the previous example, only on line 11, we are storing the reference of the function in a variable instead of invoking it.

Question 1: What will get printed in the console(line 13, 14, 15)?

You can tell the interviewer that -

When we try to invoke that method at a later point(line 12), then instead of pointing to the object(obj), it will be equal to global object or undefined.

Why?

Because, In case of object method whenever, we store the reference of the function in a variable, the binding of the object is lost and function will be invoked as a standalone function (Rule 1) at a later stage.


Question 2: How can we fix this code?

After storing the reference to the method, we lost the binding to this. Now to fix this binding issue we need to use bind() -

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var myObj = {
    a: 2,
    // foo is declared as a method
    foo: function() {
        // returning the current value of `this`
        return this;
    }
}

var bar = myObj.foo.bind(myObj);
// invoked as a standalone function(Rule 1)
console.log(bar());   // {a: 2, foo: [f]}
console.log(bar() === myObj);     // true
console.log(bar().a); 	// 2

There is a simpler way to identify the current execution context 1 in case of Rule 1 and Rule 2.

You can check if there is something present on the left-hand side of the function invocation and -

  • If yes, then this will be equal to that object
1
2
3
4
5
6
7
8
var obj = {
    a: 2,
    foo: function() {
        console.log(this);  // {a: 2, foo: [f]}, this === obj
    }
}

obj.foo();
  • Otherwise if nothing is present on the left-hand side then this will be equal to either global object or undefined
1
2
3
4
5
function foo() {
  console.log(this);	// window
}

foo();

Rule 3: Invoked using call(), apply()

This is also known as Explicit binding.

By using call() or apply() we can change the value of execution context 1(this) at the run time.

1
2
3
4
5
6
7
function foo() {
	return this;
}

console.log(foo());		// this === window
console.log(foo.call({a: 2}));		// this === {a: 2}
console.log(foo.apply({a: 4}));		// this === {a: 4}

When we invoke the function foo()

  • As a standalone function(line 5), it returned this which was equal to the global window object
  • Using call() or apply()(line 6, 7) and passed a different object to it which acts as an execution context1 for foo(), it returned the same object {a: 2}

Rule 4: Invoked with new keyword

If a function is invoked using a new keyword(as a constructor function), then the value of this inside that function is alway equal to an object.

1
2
3
4
5
6
7
8
9
10
// invoked as a constructor function
function Foo() {
    this.a = 2;
    this.b = 4;
    console.log(this);  //  {a: 2, b:4}
    console.log(window.a);  // undefined
    console.log(window.b);  // undefined
}

var bar = new Foo();

If the same function is invoked as a normal function, then this would be equal to window object and all the properties (a and b) will be created on window object.

1
2
3
4
5
6
7
8
9
10
// invoked as a normal function
function Foo() {
    this.a = 2;
    this.b = 4;
    console.log(this);   //  window
    console.log(window.a);  // 2
    console.log(window.b);  // 4
}

var bar = Foo();

ES6

Now, before we get into the interview questions. I would like to discuss the behaviour of this on some of the new concepts introduced in ES6 and later versions.

this in arrow functions

Arrow functions from ES6 do not have their own this value instead they borrow this from their lexical scope and use that value.

In the following example, bar() is an arrow function(line 8) and invoked as a standalone function, but Rule 1 will not be applied here because Rule 1 can be applied only on normal function.

this inside bar() is equal to the obj because bar() is an arrow function and it borrows this from the enclosing scope and in this case it borrows this from the function foo().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// example 1 - with arrow function
var obj = {
  a: 2,
  foo: function() {
    console.log(this);    // obj
    
    // arrow function
    bar = () => {
      console.log(this);    // obj
      console.log(this.a);  // 2
    }

    bar();
  }
}

obj.foo();

If I try to write the same function as a normal functions, then you will observe the differences in terms of their behaviour.

Here, bar() is a normal function and invoked as a standalone function. So Rule 1 will be applied here and accordingly this inside bar will point to the global window object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// example 2 - with normal function
var obj = {
  a: 2,
  foo: function() {
    console.log(this); // obj

    // normal function
    function bar() {
      console.log(this); // window
      console.log(this.a); // undefined
    }

    bar();
  }
}

obj.foo();

Cheat sheet

There is a trick that can be used to answer most of the input-output questions in an interview. You just need to check two things -

  • Is there any explicit binding is present on the function invocation - fn.call(), fn.apply(), fn.bind()
  • Is there any object present on the left side of the function invocation - obj.method()

If none of them is present, than you need to look if the code is in the strict mode or non-strict mode.

  • In non-strict mode - this = window
  • In strict mode - this = undefined

You can refer to this flow chart for more clarity -

flow chart


  1. execution context is an abstract concept that holds information about the environment within which the current code is being executed.  2 3 4

-->