How to Access the Correct “this” Inside a Callback

From time to time, the keyword this may become a source of pain for developers.

In this short tutorial, we will give the answers to one of the most common issues in JavaScript: how to access the correct “this” inside a callback.

this is a special keyword inside any function, and its value depends on how the function was called but not how, where or when it was defined. It is not affected by lexical scopes, just as other variables.

Let’s take a look at the following cases:

function func() {
  console.log(this);
} // function call 
func(); // `this` will refer to `window` 
// as object method 
let obj = {
  bar: func
};
obj.bar(); // `this` will refer to `obj` 
// as constructor function 
new func(); // `this` will refer to an object that inherits from `func.prototype`

In case you don’t want to access this but the object it refers to. A simple solution is creating a new variable, which also refers to that object. It may have any naming but the usual ones are that and self. It is demonstrated in the example below:

function ConstructorFunc(data, transport) {
  this.data = data;
  let self = this;
  transport.on('data', function () {
    console.log(self.data);
  });
}

Setting this inside the callback

You may not have control over the value of this because it is specified automatically. But it’s not that case.

Each function has the .bind method, returning a new function with this, bound to a value. The function behaves like the so called .bind on but the this is specified by you. It doesn’t matter where and when the function is called, this refers to the passed value, as follows:

function ConstructorFunc(data, transport) {
  this.data = data;
  let boundFunc = (function () { // parentheses aren’t necessary but might improve readability
      console.log(this.data);
    }
  ).bind(this); //  here we are calling `.bind()`
  transport.on('data', boundFunc);
}

In such a case, you are binding the callback this to the value of the Constructor’s this.

Please, take into account that while binding context for jQuery, you can use jQuery.proxy.

The ECMAScript 6 represents arrow functions that can be considered as lambda functions. They don’t contain this. The this can be looked up in scope as a regular variable. It means that you are not required to call .bind. But that’s not the only unusual behavior they have.

Now, let’s check out the following example:

function ConstructorFunc(data, transport) {
  this.data = data;
  transport.on('data', () => console.log(this.data));
}

The functions/methods accepting callbacks may also accept a value to which this of the callback should refer. It is the same as binding yourself, but the method/function is doing it instead of you:

arr.map(callback[, thisArg])

So, the first argument is the callback, and the value this should refer to the second one.

For instance:

let arr = [1, 2, 3];
let obj = {
  multiplier: 15
};
let newArr = arr.map(function (value) {
  console.log(value * this.multiplier);
}, obj); // here we are passing `obj` as second argument

Another common expression of this problem is when an object method is used as a callback handler. Functions are prior in JavaScript, and the term “method” is considered a colloquial naming for a function, which is a value of an object property. That function doesn’t obtain a specific link to the containing object:

Let’s consider this example:

function Func() {
  this.data = 20,
  document.body.onclick = this.method;
}
Func.prototype.method = function () {
  console.log(this.data);
};

In the example above, this.method is specified as a click event handler. In case you click the document.body, the logged value will be undefined. The reason is that inside the event handler, this refers to the document.body and not the instance Func.

As we have already noted, this always depends on how the function is called, and not on how it is defined.

In the example below, you can notice that the function doesn’t obtain an inherent reference to an object:

function method() {
  console.log(this.data);
}

function Func() {
  this.data = 20,
 document.body.onclick = this.method;
}
Func.prototype.method = method;

So, the solution will be as follows:

document.body.onclick = this.method.bind(this);

Either you can call the function as a method of the object, acting like this:

let val = this;
document.body.onclick = function () {
  val.method();
};

Another option is using an arrow function:

document.body.onclick = () => this.method();

The Description of Object methods, “this”

In JavaScript, objects are generated to represent real-world entities, such as users, orders, and so on.

Functions in properties can represent actions in JavaScript. A specific function that is the property of an object is called a method. Even more, a pre-declared function can be applied as a method.

this is a special keyword inside any function, and its value depends on how the function was called but not how, where, or when it was defined.

In comparison with other programming languages, in JavaScript, this can be used in any of the functions.


Do you find this helpful?

Related articles