TIL setTimeout, blocks, closure
POSTED ON:
TAGS: interview-questions stack-overflow closure
This is a fantastic question.
// What will the following output?
const arr = [10, 12, 15, 21];
for (var i = 0; i < arr.length; i++) {
setTimeout(function() {
console.log('Index: ' + i + ', element: ' + arr[i]);
}, 3000)
}
There's some interesting things in here:
- There's closures
- There's a callback
- There's an anonymous function
setTimeout
's callback. - We're using ES6 stuff (that const)
- How setTimeout uses the stack queue.
The result:
Index: 4, element: undefined
Index: 4, element: undefined
Index: 4, element: undefined
Index: 4, element: undefined
Step-by-step of what's happening:
- Look at the
var i = 0
element.
setTimeout is creating a closure function.
a JavaScript closure is when an inner function has access to its outer enclosing function’s variables and properties
-
The closure has access to
i
, which it will take. -
It's creating 4 anonymous functions, each one firing after 3000 milliseconds.
So....
loop 0 (i == 0) - create function.
loop 1 (i == 1) - create function
loop 2 (i == 2) - create function
loop 3 (i == 3) - create function
loop 4 (i == 4) - stop
- The anonymous function is executed AFTER 3000 milliseconds is up.
But wait, remember step 2?
Closure is taking the i
variable.
What is the i variable? Well, according to step 3, i == 4!
console.log('Index: ' + i + ', element: ' + arr[i]);
OR
console.log('Index: ' + 4 + ', element: ' + arr[4]);
**The result: **
Index: 4, element: undefined
Index: 4, element: undefined
Index: 4, element: undefined
Index: 4, element: undefined
How to Fix it #
If you swap the var
for a let
, it'll work correctly.
Because let will create a block scope.
// What will the following output?
const arr = [10, 12, 15, 21];
for (let i = 0; i < arr.length; i++) {
setTimeout(function() {
console.log('Index: ' + i + ', element: ' + arr[i]);
}, 3000)
}
// looks the same as
for (var i = 0; i < arr.length; i++) {
( function() {
var internal_i = i; // the let creates it's own block scope, which then stores i internally
setTimeout(function() {
console.log('Index: ' + internal_i + ', element: ' + arr[internal_i]);
}, 3000)
}
)
}
Index: 0, element: 10
Index: 1, element: 12
Index: 2, element: 15
Index: 3, element: 21
REF:
A Common JavaScript Interview Question Asked By Google & Amazon
why let and var behave differently - Stack overflow
Related TILs
Tagged: interview-questions