this and bind() in JavaScript

Shahrooz Me

Hi, I'm Shahrooz, a front-end developer. I'm the author of this blog, nice to meet you!

→ Follow me on Twitter!

this keyword refers to an object, that object which is executing the current bit of JavaScript.

In languages that are oriented around functions like Scheme, there is no concept of this. But in object-oriented languages this is absolutely essential for the language to work.

The word this in JavaScript means the same thing it does in English: nothing without context mean anything. For example, if you say to a friend I don’t like this, he/she have to infer from the context that you both are in what you mean by this.

In JavaScript the situation for this is different:

  • this in a function call
  • this in a method call
  • this in a constructor call
  • this with bind() method
  • this in an arrow function
  • this in browser event handler

Before starting, let’s familiarize with a couple of terms:

  • Invocation of a function is executing the code that makes the body of a function, or simply calling the function.
  • Context of an invocation is the value of this within function body.
  • Scoping answers the question “Where can we access certain variables?”
  • Method is a function attached to an object.
  • Bound function is a function connected with an object.

1. this in a function call

In a regular function call the this keyword points at the global object (the Window object in the browser).

function say(something) {
  console.log(something); // Hello
  console.log(this); // Window object
}

say('Hello');

1.2. this in a function call, strict mode

If strict mode is enabled for any function then the value of this will be undefined as in strict mode, global object refers to undefined in place of Window object.

function strictFunction() {
  'use strict';
  console.log('Simple function call'); // Simple function call
  console.log(this === window); // false
}

strictFunction();

2. this in a method call

In a method call the this keyword points to the object that is calling the method.

let company = {
  name: 'Apple',
  yearOfBirth: 1976,
  getInfo: function() {
    console.log(this); // Object {name: Apple, yearOfBirth: 1976}
    console.log(this.name); // Apple
  }
}

company.getInfo();

The same works in this example:

let company = {
  name: 'Apple',
  yearOfBirth: 1976,
}

company.getInfo = function() {
  console.log(this); // Object {name: Apple, yearOfBirth: 1976}
  console.log(this.name); // Apple
}

company.getInfo();

An arrow function does not work in the same way, as it’s lexically bound:

let company = {
  name: 'Apple',
  yearOfBirth: 1976,
  getInfo: () => {
    console.log(this); // Window object
    console.log(this.name); // undefind
  }
}

company.getInfo();

You cannot bind a value to an arrow function as you do with regular functions.
It’s not possible due to the way they work. this is lexically bound, which means its value is derived from the context where they are defined.

3. this in a constructor call

this is the newly created object in a constructor call.

Constructor call is performed when new keyword is followed by an expression that evaluates to a function object.

This example declared a function Computer, then invokes it as a constructor:

function Computer(name, bought) {
   this.name = name ? name : '';
   this.bought = Boolean(bought);
}
Computer.prototype.buy = function() {
  this.bought = true;
};

// Constructor invocation
let macbook = new Computer('macbook', false);
// Constructor invocation
let surface = new Computer;

macbook.buy(); // Buy a macbook

new Computer('macbook', false) is a constructor call of the Computer function. The result of execution is a new object which name property is macbook.
If the constructor is called without arguments, then the parenthesis pair can be omitted.

Let’s check the context of the following example:

function Country() {
  console.log(this instanceof Country); // true
  this.city = 'Montreal';
}

// Constructor call
let Canada = new Country;
Canada.city; // 'Montreal'

new Country is making a constructor call where the context is Canada. Inside Country the object is initialized and the this keyword points to the newly created object in this case Canada.

4. this with bind method

Now that you have a good understanding of what the this is, let’s dive in deeper.

Let’s say we have a dragon object.

let element = 'dirt';

let dragon = {
  element: 'fire',
  breathe: function() {
    console.log(`I am breathing ${this.element}`);
  }
}

dragon.breathe(); // I'm breathing fire

We called the breathe method which is logging the “I am breathing fire” to the console, but what if we remove the this keyword?
It will no longer point to the “fire” instead, it will points to the global variable which is “dirt”.

Now let’s take this a little bit further.

let dragon = {
  element: 'fire',
  breathe: function() {
    console.log(`I am breathing ${this.element}`);
  }
}

let dragonIsBreathing = dragon.breathe;
dragonIsBreathing(); // undefind

This undefined that we are getting here is an example of how the object-oriented nature of JavaScript clashes with its function-oriented nature.

When we are reassigning a method (dragon.breathe) to a variable (dragonIsBreathing), that variable is no longer a method, instead, it is a function and as you know in regular functions the this keyword points at the global object. So in a function the this keyword does not refer to the context where the function was defined, it refers to the context where the function is being called.

So to solve this problem we can bind it to the dragon context by using the bind() method.

let dragon = {
  element: 'fire',
  breathe: function() {
    console.log(`I am breathing ${this.element}`);
  }
}

let dragonIsBreathing = dragon.breathe;
let boundFunction = dragonIsBreathing.bind(dragon);
boundFunction(); // 'I am breathing fire'

The bind() method returns a bound function, when called, has its this keyword set to the provided value.
Notice that we can only call bind() on a function.

5. this in an arrow function

this is the enclosing context where the arrow function is defined.

The arrow function doesn’t create its own execution context, but takes this from the outer function where it is defined as it’s lexically bound.

The following example shows the context transparency property:

class Person {
  constructor(age, color) {
    this.age = age;
    this.color = color;
  }

  log() {
    console.log(this === Anna); // true
    setTimeout(() => {
      console.log(this === Anna); // true
      console.log(this.age + ' - ' + this.color); // 20 - white
    }, 1000);
  }
}

let Anna = new Person(20, 'white');
Anna.log();

setTimeout is calling the arrow function with the same context (myPoint object) as the log() method. As seen, the arrow function “inherits” the context from the function where it is defined.

If trying to use a regular function in this example, it would create its own context (Window or undefined in strict mode). So to make the same code work correctly with a function expression it’s necessary to manually bind the context: setTimeout(function() {...}.bind(this)). This is verbose, and using an arrow function is a cleaner and shorter solution.

If the arrow function is defined in the top most scope (outside any function), the context is always the global object (Window in a browser):

let getContext = () => {
   console.log(this === window); // true
   return this;
};

console.log(getContext() === window); // true

6. this in browser event handler

In event handlers callbacks, this refers to the HTML element that received the event:

document.getElementById('myButton').addEventListener(
  'click',
  console.log(this); // HTMLElement
);

You can bind it:

document.getElementById('myButton').addEventListener(
  'click',
  function(e) {
    console.log(this); // Window if global, or your context
  }.bind(this);
);

SUMMARY

  • In a regular function call the this keyword points at the global object (the Window object in the browser).
  • In strict mode global object refers to undefined in place of Window object.
  • In a method call the this keyword points to the object that is calling the method.
  • In a constructor call the this keyword is the newly created object in a constructor call.
  • The this keyword is attached to the execution context which is only created as soon as a function is called (invoked).
  • In event handlers callbacks, this refers to the HTML element that received the event.