Close menu

What The Heck Is this?!

It's all about context. This is true in general, but even moreso for JavaScript.

Unlike other languages, the value of the this keyword in JavaScript depends on a number of factors. It's value will change depending on the context it is used in, but also the mode in which the code is executing, and within the function context, the way in which the function is called as well as the type of function used.

To make things a little more interesting, you can even set the value when calling a function!

Global Context

When referenced in the global context (e.g. in window or worker contexts), this is always a reference to the global object itself.


console.log(this);  // logs the 'window' object

Function Context

Here's where things get a little messy…

Direct Execution

When functions are executed normally, in non-strict (or 'sloppy') mode, this will be the global object.


function whatTheHeckIsThis() {
  return this;
}

whatTheHeckIsThis();  // returns the 'window' object

However in strict mode, functions called directly like this will have this set to undefined . This is because we haven't explicity set the value of this when we called the function, nor is the function being called as a method of any object.


function strictWhatTheHeckIsThis() {
  'use strict';
  return this;
}

strictWhatTheHeckIsThis();  // returns undefined

As an Object Method

But, in any mode, and wherever it may be defined, if an object is executed as a method of some instance/object, this is bound to the instance/object for which the function is a method.


function whatTheHeckIsThis() {
  return this;
}

var widget = {
  foo: whatTheHeckIsThis
}

widget.foo();  // returns 'widget'

As an Event Handler

Similarly, when a function is used as an event handler for a DOM node, then this is bound to that DOM node.


function whatTheHeckIsThis() {
  return this;
}

var el = document.getElementById('foo');

el.addEventListener(
  'click',
  whatTheHeckIsThis   // the DOM node i.e. 'el'
);

Setting A Custom this

You can call functions and explicitly bind this to a value of your choice… well, sort of…

Using call & apply

Functions don't always have to be executed directly, with call & apply, you can execute a function while specifying a value to use for this.

They both do the same thing, and the first argument for both is the value to use for this. The difference is that call accepts a list of comma seperated values as additional arguments, while apply accepts a single array of values as an aditional argument. We'll just look at call as an example.


function whatTheHeckIsThis() {
  return this;
}

var that = {
  foo: 'bar'
};

whatTheHeckIsThis.call(that);  // returns 'that'

But if only it were that simple!

In sloppy-mode, this must always be an object, so if you supply null or undefined, the global object is used, but if you provide a primitive value, then JavaScript will instantiate a new instance using that primitive's Object constructor.


function whatTheHeckIsThis() {
  return this;
}

whatTheHeckIsThis.call(null);   // the 'window' object
whatTheHeckIsThis.call(123);    // a 'Number' instance
whatTheHeckIsThis.call('abc');  // a 'String' instance
whatTheHeckIsThis.call(false);  // a 'Boolean' instance

But in strict mode, you can provide any value whatsoever, and that exact value is what will be used!


function strictWhatTheHeckIsThis() {
  'use strict';
  return this;
}

strictWhatTheHeckIsThis.call(null);   // null
strictWhatTheHeckIsThis.call(123);    // 123
strictWhatTheHeckIsThis.call('abc');  // 'abc'
strictWhatTheHeckIsThis.call(false);  // false

Using bind

This method returns a copy of a function, with it's this value bound to the supplied argument. Whatever way you call it, it will always use the supplied value for it's this value.


function whatTheHeckIsThis() {
  return this;
}

var myThis = { a: 123 };
 
var boundThis = whatTheHeckIsThis.bind(myThis)

boundThis();             // returns 'myThis'
boundThis.call(123);     // returns 'myThis'
boundThis.apply('abc');  // returns 'myThis'

Arrow Functions

ES6 introduced 'arrow functions', which provide anonymous function with terser syntax & the option for implicit returns - but that's not all they do.

An arrow function has a specific feature; they do not set or change the value of this. In an arrow function, this is determined by it's enclosing lexical scope.


// So in global contexts...

console.log(this);        // the 'window'

var whatTheHeckIsThis = () => this;
 
whatTheHeckIsThis();      // the 'window'

// While in function contexts...

function whatTheHeckIsThis() {
  'use strict';
  function standardFunctionThis() {
      return this;
  };
  var arrowFunctionThis = () => this;
  
  console.log(
      standardFunctionThis(),
      arrowFunctionThis()
  );
 }

whatTheHeckIsThis();  // logs 'undefined, undefined'

var myThis = { a: 123 };

whatTheHeckIsThis.call(myThis);  // logs 'undefined, myThis'

That's a quick overview of this. Hopefully it's made things a little clearer if you were struggling with it.

this is a very important keyword for JavaScript, and despite it's confusing implementation, and what seems to be an ever-changing value, it allows you to write better, more contextually catered, as well as reusable code - so be sure to make use of it!

First published: 22/07/2020