DEV Community

Dharan Ganesan
Dharan Ganesan

Posted on • Edited on

Day 14: This is lost

In JavaScript, the context of this can be lost in certain situations, leading to unexpected behavior.

Passing a Method as a Callback:

When you pass a method as a callback function to another function or event handler, the context of this can change unexpectedly.

const obj = {
  nom: 'John',
  sayHello: function() {
    console.log(`Hello, ${this.nom}!`);
  }
};

// Using the 'sayHello' method as a callback to setTimeout
setTimeout(obj.sayHello, 1000); // output: Hello, undefined!
Enter fullscreen mode Exit fullscreen mode

when setTimeout executes the sayHello method, the context of this is no longer obj, but it becomes the global object. As a result, this.nom will be undefined.

To solve this issue, you can use function borrowing to explicitly set the context of this before passing the method as a callback

setTimeout(obj.sayHello.bind(obj), 1000);
// or
setTimeout(() => obj.sayHello(), 1000);
// or
setTimeout(function() {
  obj.sayHello();
}, 1000);
Enter fullscreen mode Exit fullscreen mode

Invoking a Method Returned from a Function:

Another common scenario where the context of this can be lost is when invoking a method returned from another function

function createCounter() {
  return {
    count: 0,
    increment: function () {
      this.count++;
    },

    getCount: function () {
      console.log(this.count);
    },
  };
}

const counter = createCounter();
const incrementFn = counter.increment;
incrementFn(); // What will happen here?
Enter fullscreen mode Exit fullscreen mode

when we assign counter.increment to incrementFn, it loses its association with the counter object. So, when we call incrementFn(), this inside the increment function becomes the global object (window or global), and count will not be accessible.

To preserve the correct context of this, you can use bind

const incrementFn = counter.increment.bind(counter);
incrementFn(); // Output: 1
Enter fullscreen mode Exit fullscreen mode

Summary:-

Being mindful of these situations where the context of this can be lost is crucial to writing correct and predictable JavaScript code. Using appropriate binding techniques or arrow functions can help ensure that this behaves as expected in different contexts.

Top comments (4)

Collapse
 
kendev2611 profile image
Minh Tran

When assigning the counter.increment to incrementFn, I see it still associates to the original counter without binding it. Could you explain it please?

Collapse
 
kendev2611 profile image
Minh Tran • Edited
function createCounter() {
  return {
    count: 0,
    increment: function () {
      this.count++;
    },

    getCount: function () {
      console.log(this.count);
    },
  };
}
Enter fullscreen mode Exit fullscreen mode

The example function should be like this. Your example is for closure I think

Collapse
 
dhrn profile image
Dharan Ganesan

Yes, this appears to be accurate and updated. Thank you for your attention to detail.

Collapse
 
dhrn profile image
Dharan Ganesan

You are indeed correct; the issue arises due to closure. I appreciate your insight.