DEV Community

Md. Imran Hossain
Md. Imran Hossain

Posted on

binding "this"

this keyword references an object. Using this keyword we may access the properties and methods of a class/object. Previously, I discussed the use-cases of this in this article. The summery is:

  1. If a function is not part of any object, it will simply reference the global window object.
  2. If a function is a part of an object, we call it as method. Inside a method thisreferences the object.

The main problem arises when we use a function(i.e. a callback function) inside that method of an object, this references the global window object and we may want to access(bind) the object and redefine the this inside the callback function.
Let’s see the problem first:

const books = {
  author: "john doe",
  books: ["history", "english", "math"],
  findBooks() {
    this.books.forEach(function (item) {
      console.log(`${this.author} like ${item}`);
    });
  },
};
books.findBooks();
Enter fullscreen mode Exit fullscreen mode

Books is a simple object which has author and books properties and a method "findbooks".
"findBooks" simply logs the author and books information. Inside the "findBooks" function we have used a "foreach" method that has a callback function. Now the output should print:

‘john doe like history’,
‘jhon doe like english’
‘john doe like math’

Let’s see the output:
Image description

So we see this.author does not print the author name. So what’s happened actually? You see, this line of code console.log(${this.author} like ${item}) is inside the callback function and the callback function is a regular function, has different execution context and references the window object(recalling the summery 1 above). In short, callback function is not a part of the object it is inside.

So how do we access the object using this?
This is the concept behind binding data or binding object.
There are three different scenarios by which may access/bind the object inside the callback function.

1. Using Arrow function:
Unlike regular function, Arrow function uses the surrounding scope as the scope of this, So whatever the surrounding scope is becomes the scope of an arrow function.

const books = {
  author: "john doe",
  books: ["history", "english", "math"],
  findBooks() {
    this.books.forEach((item) => {
      return console.log(`${this.author} like ${item}`);
    });
  },
};
books.findBooks();
Enter fullscreen mode Exit fullscreen mode

Output:
Image description

Now, the callback function doesn’t have it’s own scope rather it uses the findbooks methods scope.

2. Explicit bind method:
So I was thinking, If we stick to the regular function(as callback), there must be a way to bind the object.
This question has an answer too. We may use bind method to get access the object.

const books = {
  author: "john doe",
  books: ["history", "english", "math"],
  findBooks() {
    this.books.forEach(
      function (item) {
        return console.log(`${this.author} like ${item}`);
      }.bind(this)
    );
  },
};
books.findBooks();
Enter fullscreen mode Exit fullscreen mode

Output:
Image description

this inside the bind method creates a little confusion. But fear not! see, we have access to this (books) object inside foreach. So, bind method also have access too. Now the regular callback function is binded with this object.

3. Assigning ‘this’ to a variable:

const books = {
  author: "john doe",
  books: ["history", "english", "math"],
  findBooks() {
    let self = this;
    this.books.forEach(function (item) {
      return console.log(`${self.author} like ${item}`);
    });
  },
};
books.findBooks();
Enter fullscreen mode Exit fullscreen mode

Output:
Image description

We have assigned this to a variable(self) and use it inside the callback function. It is basically the closure concept that will not be covered in this article. But what it does, we get access to the variable declared in the parent function inside the child function . In this way, the self variable gets the reference of this, and later we used it inside the callback function.

Discussion (0)