Mark Pollmann
BooksAbout

The this keyword in Javascript

3 minutes read

This post serves as a quick refresher on how the this-keyword works in different contexts in the JavaScript language. It might help someone to not fall for one of the many traps I already fell for.
Note that I will only talk about strict mode here. Sloppy mode has way too many gotchas on its own and is generally discouraged. Going forward, ES6 modules will always be in strict mode, anyway.

this in the global context

Calling this in the global execution context (outside of any function) refers to the global object. In the browser the global object is called window, in Node.js it's called global. But beware: in node modules the code is wrapped in a wrapper function, so this now points to module.exports.

this in function calls

The this value in a regular function call is undefined (in sloppy mode it referred to the global object):

"use strict"
function Foo() {
  console.log(this)
}
Foo() // undefined

this in constructor calls

Calling a function with new is called a constructor call. A new object will be created and this set as a reference to this instance. This works as expected and is pretty straight-forward:

function Something(first, second) {
  console.log(this)
  this.firstName = first
  this.secondName = second
}
const foo = new Something("John", "Doe") // Something {}
console.log(foo.firstName) // 'John'

this in method calls

In method calls this refers to its receiver, the object on which the method was invoked on:

const o = {
  f: function() {
    console.log(this)
  },
}
o.f() // { f: [Function: f] }

Another object could call o.f() and this would still refer to the original o object.

this in call() or apply()

With call and apply you can set the this value for this one time explicitly. They differ only in the way you are able to additionally set arguments: either comma-separated with call or in an array with apply.

function f(a, b) {
  console.log(this) // 'new this value'
  console.log(a) // 'firstArg'
  console.log(b) // 'secondArg'
}
f.call("new this value", "firstArg", "secondArg")
f.apply("new this value", ["firstArg", "secondArg"])

If you keep forgetting which one takes an array and which one doesn't: apply and array both start with a and each has five letters.

this in bind()

ES5 introduced function.prototype.bind(thisArg [, args]). This creates a new function with this permanently bound to the used thisArg (as well as optional, comma-separated, arguments).

function foo() {
  console.log(this)
}
foo() // undefined
const bar = foo.bind("newThis")
bar() // 'newThis'

this in arrow functions

Arrow functions don't bind this (neither arguments, super and new.target):

function f(a) {
  const anon = c => {
    return console.log(arguments)
  }
  anon("new arg")
}
f("old arg") // { '0': 'old arg' }

No need for the const self = this hack if used properly.

this in ES6 classes

While I'm not a fan of them, ES6 introduced classes anyway. Under the hood they still work with the JavaScript prototype system and are basically syntactic sugar over it.
this inside a normal class method refers to the instance, in static methods to the class itself.

class Foo {
  constructor() {
    console.log(this)
  }
  static bar() {
    console.log(this)
  }
}
const foo = new Foo() // instance of Foo
Foo.bar() // class Foo

Conclusion

There are lots and lots of edge cases for this that I haven't talked about here which could fill books. I try to code without this as much as possible and it works out fine (usually).