[JavaScript] The Secret of the setTimeout - this

ยท

3 min read

How does "this" work in setTimeout?

Before we start to talk about the topic. Let's start a simple example to recall "this". For example, to get cx60, we will call the car.printModel(). Pretty straightforward.

const car = {
    model: 'cx60',
    printModel() {
        // 'this' refer to the car object
          console.log(this.model);
    }
}

car.printModel(); // "cx60"

Next, how to get cx60 after 1000 ms? It is not difficult, just execute the car.printModel() inside of the setTimeout like this setTimeout(car.printModel, 1000). Wait, what result will we get? undefined rather than cx60.

But, Why ????

Because of this , this keyword usually makes confusing when learning JS ๐Ÿฅฒ. If put car.printModel inside of the setTimeout like this example, setTimeout(car.printModel, 1000) , it would consider it scope is window .

Before we fix it, I want to show you one example to make it clear why this situation happened. For the following example, declared a parameter c and assign car.printModel rather than call it. Now, its scope will refer to the window . We will get undefined rather than cx60 .

// this scope is window
const c = car.printModel;
c(); // undefined

How could we fix it ? Use a wrapper function or bind()

// wrapper function
const anrrowWrapperC = () => { car.printModel() }; // arrow function
anrrowWrapperC() // "cx60"
const declaredWrapperC = function { car.printModel() }; // normal declared function
declaredWrapperC() // "cx60"

const c = car.printModel;
const bindC = c.bind(car);
bindC(); // "cx60"

If we take a close look when use wrapper function. We will find car.printModel() still executed by itself when call wrapperC, rather than assign to other declare parameter to execute (such as c in the previous example). Using the wrapper function here, just like take out of wrapper function to execute car.printModel() , so its this keyword still refer to car object. There is a little bit difficult to understand why no different when using arrow function and normal declared function will get the same result. I think This is the reason why arrow function and normal declared function will not affect this here of its scope. (Probably is easy for you, but I spent a few time trying to understand ๐Ÿค”)

I didn't give much explanation here when use bind because I think it is intuition solution.

Solution & Conclusion

If you read carefully before, you definitely know the solution to setTimeout(car.printModel, 1000) . Yes, use a wrapper function or bind(). ๐Ÿš€

// Solution 1: Wrapper function
setTimeout(function() { // normal declared function
  car.printModel();
}, 1000) // "cx60"

setTimeout(() => { // arrow function
  car.printModel();
}, 1000) // "cx60"

// Solution 2: Use bind function
setTimeout(car.printModel.bind(car), 1000); // "cx60"

Thanks for the reading. Welcome to leave the comments to discuss further. ๐Ÿค—

Reference

[MDN] setTimeout() global function - The "this" problem

ย