What is 'this' in JavaScript?

What this means in JavaScript is often one of the trickiest thing to understand. In short, this refers to the current execution context.

Global context

When outside of any functions or classes (which are actually just functions), this refers to the global execution context, which is window when inside a web browser.

this; // window
this.foo = "bar";
window.foo; // "bar"

In Node.js, this in the global context refers to the exports object, which is, by default, an empty object.

this; // {}

Function context

When inside a function, the value of this is determined by how the function is called. For example:

const bar = function () { console.log(this) };
const foo = {};
foo.bar = bar;

bar(); // window
foo.bar(); // bar

Function

When the function is called inside the global context, then this refers to the global execution context.

const bar = function () { console.log(this) };
bar(); // window

The function block does not affect the execution context of its body.

const foo = function () { bar(); }
foo(); // window
Strict Mode

Inside a function, the value of this is also determined by whether strict mode is on. Without strict mode, it will be the global object (window); with strict mode, it will be undefined.

const foo = function () { console.log(this) };
const bar = function () { 'use strict'; console.log(this); };

foo(); // window
bar(); // undefined

Function Constructor

A function can be used as a function constructor when used with the new keyword. Function constructors act as templates that creates new objects, and is sugarized into classes in ECMAScript 2015 (ES6).

When a function is used as a function constructor, this inside the function body refers to the object that's being constructed.

function Car(make) {
  this.make = make;
}

const myCar = new Car("BMW");
myCar.make; // "BMW"

Since function constructors are sugarized into classes in ES6, the same is true for ES6's class constructor.

class Car {
  constructor(make) {
    this.make = make;
  }
}

const myCar = new Car("BMW");
myCar.make; // "BMW"

Prototype

A function constructor can also have a method defined in its prototype object. this refers to the object instance that is calling this method.

Car.prototype.getMake = function () {
  return this.make;
}

myCar.getMake(); // "BMW"

Again, the prototype object is equivalent to the prototype methods of a class, so the same rules for this applies.

class Car {
  constructor(make) {
    this.make = make;
  }

  getMake() {
    return this.make;
  }
}
const myCar = new Car("BMW");
myCar.getMake(); // "BMW"

Object Method / Static Method

If the function is a method of an object, this refers to the object.

const foo = {};
foo.bar = function () { console.log(this); };
foo.bar(); // foo

Since every function is an object in JavaScript, this is equivalent to a static method inside a JavaScript class.

class Car {
  constructor(make) {
    this.make = make;
  }

  static convertKmToMiles(km) {
    return km * this.kmToMilesConversionRate;
  }
}
Car.kmToMilesConversionRate = 0.621371;
Car.convertKmToMiles(42); // 26.097582

Another example of this is when you run window.setTimeout. Inside setTimeout, this refers to the window object.

const foo = {};
foo.bar = function () {
  window.setTimeout(function () {
    console.log(this);
  }, 0);
};
foo.bar(); // window

Binding this

.bind

If you want to ensure that this inside the function always refers to a certain object, you can use the bind method of the function.

const foo = function () { console.log(this) };
const boundFoo = foo.bind("always me!");

foo(); // window
boundFoo(); // "always me!"

const a = {
  b: foo,
  boundB: boundFoo
}
a.b(); // a
a.boundB(); // "always me"

bar = function () {};
bar.prototype.x = foo;
bar.prototype.boundX = boundFoo;

const myBar = new bar();

myBar.x(); // myBar
myBar.boundX(); // "always me"
.call and .apply

Function.prototype.bind returns a new function with this bound to an object, but does not invoke the function. Function.prototype.call and Function.prototype.apply immediately invokes the function, passing in the this value along with it.

The only difference between .call and .apply is that .call expects the arguments to be listed out directly, whereas .apply expects the arguments to be grouped into an array.

const foo = function (x, y) {
  console.log(this);
  console.log(x);
  console.log(y);
};

foo(); // window, undefined, undefined
foo.call(); // window, undefined, undefined
foo.call("Yo!"); // "Yo!", undefined, undefined
foo.call("Yo!", 1, 2); // "Yo!", 1, 2
foo.apply("Yo!", [1, 2]); // "Yo!", 1, 2

ES6 / 7

In ES6, there are two new syntax that affects the way this is bound:

  • Arrow functions
  • Reflect.apply()

In ES7, there's a new :: bind operator.

Arrow functions

Arrow functions automatically binds the context of this inside its function body.

function Car (make) {
  window.setTimeout(function () {
    console.log(this); // window
  }, 0);
  window.setTimeout(() => {
    console.log(this); // Car
  }, 2000)
}

new Car();
// window
// Car
Reflect.apply()

Reflect.apply is another way to write Function.prototype.apply.

const foo = function (x, y) {
  console.log(this);
  console.log(x);
  console.log(y);
};

foo.apply('a', ['b', 'c']); // 'a', 'b', 'c'
Reflect.apply(foo, 'a', ['b', 'c']) // 'a', 'b', 'c'

They are equivalent with a few caveats, the most relevant of which is that you can override the apply method of an object, whereas Reflect.apply will always equal Function.prototype.apply

foo.apply = function(x, y) { console.log(y.concat([x])) };
foo.apply('a', ['b', 'c']); // ['b', 'c', 'a']
Reflect.apply(foo, 'a', ['b', 'c']) // 'a', 'b', 'c'
:: bind operator

The :: bind operator is a proposed operator that binds the method of an object to the object itself.

console.log(this); // window
console.log(this).bind(console); // console
::console.log(this); // console

Daniel Li

Full-stack Web Developer in Hong Kong. Founder of Brew.

Hong Kong http://danyll.com