[JavaScript] The Secret of the setTimeout - this
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. ๐ค