JavaScript and ‘this’

Keeping your head square about JavaScript’s this variable can be a little challenging. A wonderfully concise summary on the issue is found in chuckj’s answer to a StackOverflow question (modified here to account for differences between ECMAScript 5’s strict and non-strict modes):

this can be thought of as an additional parameter to the function that is bound at the call site. If the function is not called as a method then the global object (non-strict mode) or undefined (strict mode) is passed as this.”

Let’s see what this means (pun intended?) for various scenarios.

Disclaimer

Here I’m only concerned with functions and methods that use conventional function definition syntax. Things behave a little differently when using ES6’s arrow functions.

While I use function expressions throughout, the results are unchanged if you use function declarations. The results shown are also unchanged if you use ES6’s let instead of var to define variables.

Unattached functions

With unattached functions running in non-strict mode, this will be the global object, which in the browser is the window.

var foo = function() {
  console.log(this); // this is the window
};

foo();

In strict mode, this will be undefined.

'use strict';
var foo = function() {
  console.log(this); // this is undefined
};

foo();

Nested functions

The same rule applies to nested functions: this will be global object (window in browsers) in non-strict or undefined in strict mode:

var foo = function() {

  var bar = function() {
    console.log(this); // window (or undefined in strict mode)
  };

  bar();
  console.log(this); // window (or undefined in strict mode)
};

foo();

Closures

Again, the same rule: this will be the global object (window) or undefined depending on strict-mode.

var foo = function() {

  var bar = function() {
    console.log(this); // window (or undefined in strict mode)
  };

  return bar;
};

var cl = foo();
cl();

Methods

With methods, this will be bound to the object, independent of strict mode.

var ob1 = {
  who: 'an object',
  foo: function() {
    console.log(this); // this is ob1
  }
}

ob1.bar = function() {
  console.log(this); // this is ob1
};

ob1.foo();
ob1.bar();

Methods with nested functions

A bit of a surprise here perhaps. Functions nested in methods are attached to the global object (window) or undefined. The way to think about this is, “Nested functions are not methods.”

var ob1 = {
  who: 'an object',
  foo: function() {
    var bar = function() {
      console.log(this); // this is the window (or undefined in strict mode)
    };

    bar();
    console.log(this); // this is ob1
  }
}

ob1.foo();

Methods with Closures

If you’re adventurous enough to use a method with a closure, “Nested functions are not methods,” again applies.

var ob1 = {
  who: 'an object',
  foo: function() {
    var bar = function() {
      console.log(this); // this is the window (or undefined in strict mode)
    };

    return bar;
  }
}

var cl = ob1.foo();
console.log(cl());

Overriding the context

You can override the default context with the apply and call methods.

var ctx = {
  who: 'ctx'
};

var foo = function() {
  console.log(this); // in both calls, this is the ctx object
};

foo.apply(ctx);
foo.call(ctx);

Summing up

Given what we’ve learned, we can distill things down into a very concise this mantra:

“Functions use the global object or undefined, methods use the object.”

This mantra applies to functions defined using classic function definition syntax. When using ES6’s arrow functions, things will change.

One thought on “JavaScript and ‘this’”

Leave a Reply

Your email address will not be published. Required fields are marked *