Understanding this Keyword in JavaScript

Note: This post is work-in-progress learning-note and still in active development. This was initially drafted on March 8 and updated recently.

In JavaScript (JS), use of function’s this keyword is very confusing, it means different thing depending on the context how a function is called. There is also some difference in whether this is called in strict mode or non-strict mode. For example, Is it used outside of a function? Is it a regular function call? Methods in ES6 classes? Called in an arrow function? etc. Based on how a function is called, value of this could be different. Even more confusing is that this keyword will have different value in the same function depending upon whether it is called as a  object method or callback function.

In this learning-note post, how the value of this keyword differs in different context is discussed.

1. Global Context

When this keyword is used outside of a function in a browser, it refers to global object. In a a browser, global object refers to window.

//used in browser 
console.log(this === window); // OUTPUT =>true
//assign variable
greeting = "Hello World!";
console.log(window.greeting); // OUTPUT =>Hello World!
// this.var asignment
this.year = 2018;
console.log(window.year); // OUTPUT => 2018
console.log(year); // OUTPUT => 2018

In the example above, this when used in a browser refers to window (line 2). Likewise, a global variable (outside of a function) also refers to window (lines: 4-5). In line 7, this.year is assigned to 2018, which refers to window object as well (lines: 8-9).

2. Simple Function Call

When calling a function in non-strict mode, this refers to global object, which is window in a browser.

//define a function
function greeting() {
  return this;
}
//in a browser
greeting() === window; // OUTPUT = true

In non-strict mode, this in function call refers to global (window) object (line: 6) because the value of this is not set by call. In strict mode, the value of this remains at whatever it was set to when entering the execution context.

//simple function
function greeting() {
  'use strict'; //strict mode
  return this;
}
//invoke greeting()
greeting(); // OUTPUT => undefined
greeting() === undefined; // OUTPUT => true

In the example above, this defaults to undefined (lines: 13-14) because it was not defined and called directly not as method or property of an object (see explanation below).

Setting a this Value: Value of this keyword can be set to current context by assigning a value to this as shown in the example below:

//define a function
function greeting() {
  this.msg = "Hello World!";
  return this;
}
//in a browser
console.log(greeting()); //OUTPUT => window
console.log(new greeting()); //OUTPUT => greeting {msg: "Hello World!"}

In the example above,  the greeting() logs to global (window) scope (line 7). However when it is invoked with new constructor operator as new greeting() it returns as greeting {msg: "Hello World!"} because the new operator bounds the value of this to the instance greeting() as shown in line 8.

Passing the value of this from one context to another will be discussed below in a separate section.

a. Setting this value with call(), apply() & bind() Methods

When a function is called directly or a property of an object then it returns global (window) because this is not bound and not aware of its calling function. This problem can be fixed by passing this value from one context to another using <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call" target="_blank" rel="noopener">call()</a> or <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply" target="_blank" rel="noopener">apply()</a> method as shown below:

// define helloWorld object
var helloWorld = {msg: 'Hello World!'};

//global context
var msg = "Hello USA!";

// define function
function valueOfThis() {
  return this.msg; // value depends how it is called
}
//invoke function
valueOfThis(); // OUTPUT => "Hello USA!"
//set with call()
valueOfThis.call(helloWorld); // OUTPUT => "Hello World!"
//set with apply()
valueOfThis.apply(helloWorld); // OUTPUT => "Hello World!"

In the example above (adopted from MDN) value of this keyword in valueOfThis() call (line ) refers to global variable "Hello World!" defined inline 5. If and when a this keyword is used in function body (eg. valueOfThis() in line 9), then value of this can be bound to an object in the function call using the call() and apply() methods.

All functions inherit call(), apply(), bind() methods from <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function#Methods" target="_blank" rel="noopener">function.prototype</a>, which are defined in MDN documents as follows:

  • Function.prototype.apply(): Calls a function and sets its this to the provided value, arguments can be passed as an Array object.
  • Function.prototype.call(): Calls (executes) a function and sets its this to the provided value, arguments can be passed as they are.
  • Function.prototype.bind(): Creates a new function which, when called, has its this set to the provided value, with a given sequence of arguments preceding any provided when the new function was called.
b. Using this with bind() Method

The bind() method attaches an object to a function permanently so that when the function is called it refers to the same bound object. To quote from MDN – when a such an object bound function is called it “creates a new function with the same body and scope as the object-bound function, but where this occurs in the original function, in the new function it is permanently bound to the first argument of bind, regardless of how the function is being used”.

Lets examine this in the following example:

//function with this in the body
function greeting() {
  return this.msg;
}
//bind object with function
let bindValue1 = greeting.bind({msg: 'Hello World!'});
console.log(bindValue1()); //OUTPUT => Hello World!

//re-assign new value to org arg
let bindValue2 = bindValue1.bind({msg: 'Hello USA!'});
//bind value can't be modified
console.log(bindValue2()); //OUTPUT => Hello World!

In the example above (adapted from MDN), this keyword is used in greeting() function body (lines: 2-4). The greeting() function is bind with msg object in line 6, which outputs expected Hello World! (line 7). The bind() method works only once (line 10) and the original value can’t be re-assigned (line 12).

3. In Object Methods

A method is a function and its an property of an object. The MDN states that “when a function is called as a method of an object, its this is set to the object the method is called on“.

In the example below, helloWorld object (line 2) has msg() method defined inside body (lines: 5-7). When helloWorld.msg is invoked (line 10), value of this inside msg() method (line 10) refers to helloWorld object where it is bound.

//expression function
const helloWorld = {
  greeting: "Hello World!",
  // define method
  msg() {
    console.log(`${this.greeting} We are live.`);
  }
};
//invoke
helloWorld.msg(); // OUTPUT => Hello World! We are live.

In the above example, the msg() function is defined during helloWorld object definition method. Behavior of this is not affected how or where the function is defined.

//define object
var helloWorld = {
  greeting: "Hello World!"};

//define function
  function msg() {
    return this.greeting;
  }
//assign function to variable
helloWorld.msg = msg;
//invoke function
console.log(helloWorld.msg()); //OUTPUT => Hello World!

In the example above, helloWorld object (line: 12-13) is defined. The this keyword is used in msg() function (line 17) and attached to earlier object as helloWorld.msg (line 20), which returns the same output (line 22) as in previous example (line 10). It is important that when invoked function should be member of the object.

4. In Constructor Operator Context

Value of this keyword can be set to current context by assigning a value to this as shown in the example below:

//define a function
function greeting() {
  this.msg = "Hello World!";
  return this;
}
//in a browser
console.log(greeting()); //OUTPUT => window
console.log(new greeting()); //OUTPUT => greeting {msg: "Hello World!"}

In the example above,  the greeting() logs to global (window) scope (line 7). However when it is invoked with new constructor operator as new greeting() it returns as greeting {msg: "Hello World!"} because the newoperator bounds the value of this to the instance greeting() as shown in line 8. Passing the value of this from one context to another will be discussed below in a separate section.

The value of this keyword is bound to the newly constructed object, when a function is used to create new object instance using new keyword. Using the previous example with some modification:

//function expression
function greeting() {
  this.text = "Hello World!";
}
//create new greeting instance
let annoucement = new greeting();
console.log(annoucement.text);  //OUTPUT => Hello World!

In the example above, the value of this.text (line 3) from greeting() is bound to newly constructed object instance of greeting() stored in annoucement variable (line 6) and hence returns correct text value in console output (line 7).

//function expression
function localGreeting() {
  this.text = "Hello World!";
  return {text: "Hello USA!"};
}
//create new localGreeting instance
let annoucement = new localGreeting();
console.log(annoucement.text); //OUTPUT => Hello USA!

In the example above, because localGreeting() was returned during the object instance construction, the bound this.text = "Hello World!" gets discarded (line 10). Therefore, in the newly created object instance the text (line 14) refers to the returned value from line 11 and NOT the this bound value from line 10.

5. In Arrow Functions

The arrow functions don’t have their own this keyword, this refers the value of enclosing lexical scope. In global context, its value is set to global object (which is window object in a browser line 6) as shown below:

//initialize global object
let globalObj = this;
//arrow function
let myFunc = (() => this);
console.log(myFunc() === globalObj); // OUTPUT => true
console.log(myFunc() === window); // OUTPUT => true

In the example above, value of this is stored in globalObj variable (line 2). When it is compared with this value stored inside myFunc() arrow function (line 4) it outputs true (line 5) which is equivalent to window object in browser (line 6).

The value of this in arrow function can’t be SET explicitly. That means value of this can’t be modified with  apply(), call() or bind() methods. The value of this refers permanently to the value set when the arrow function was created.

// call as a method of an object
let localObj = {otherFunc: myFunc};
console.log(localObj.otherFunc() === globalObj); // OUTPUT => true

// set this with call()
console.log(myFunc.call(localObj) === globalObj); // OUTPUT => true

// set this with bind()
myFunc = myFunc.bind(localObj);
console.log(myFunc() === globalObj); // OUTPUT => true

In the above example (adopted from MDN), the value of this in myFunc() arrow function was set to globalObj (line 2) when it was created. The value of this can’t be modified from the original globalObj by calling as a method of an object (line 8-9), or set explicitly using call() method (line 12) or bind() method (lines: 15-16).

The value of this in arrow functions created inside other function, will have the same value that of enclosing lexical context. Revisiting example used the Understanding JavaScript Arrow Function post as shown below:

//create helloWorld object
let helloWorld = {
  greeting: "Hello World!",
  //define method
  msg: function() { 
    console.log(`${this.greeting} We are live.`);
    //autonomous arrow function
    setTimeout(() => {
      console.log(this.greeting)
    }, 1000)
  }
}
//invoke
helloWorld.msg(); //OUTPUT =>Hello World! We are live.
//after timeout -- greeting 
Hello World!

In the example above, value of this in msg() refers to helloWordl object loging msg.greeting within the function (line 5) correctly prints "hello World! in the output (line 14). When a second setTimeout() arrow function is added (lines: 8-10 ), the context of this.greeting is different.

Because arrow functions take their value of this from the lexical scope (meaning from its surrounding block) and thus captures this from its surrounding context helloWorld (line 2) where it is defined. This is discussed in more detail in arrow function post’s No Separate this binding section.

6. In DOM Event Handler

The this keyword use in DOM event handler is discussed in the MDN where this is set to element where it is fired from. This topic will be discussed in a separate post later.

Wrapping Up

Until recently I was very confused with this keyword in JavaScript. Because I was just starting to learn JS Basics it didn’t make much sense to me and was a mystery. When I did a google search with ‘this in JavaScript‘, I found many detailed posts about the use of  this keyword. Indeed I was not alone to get confused.  A clear understanding of this keyword is important.

Useful Resources and Links

While preparing this post, I have referred the following references extensively. Please to refer original posts for more detailed information.