Closure Q1
What would this print out?
var arr = [1,2,3,4];
function closure(){
for(var i = 0; i < arr.length; i++){
setTimeout(function(){
console.log(i)
}, 100)
}
}
closure()
var arr = [1,2,3,4];
function closure(){
for(var i = 0; i < arr.length; i++){
setTimeout(function(){
console.log(i)
}, 100)
}
}
closure();
It would print out:
4
4
4
4
This is because the function gets called and the loop happens, but the setTimeout
isn't called until later (because of the timeout) and at that point, the i
is at 4
because the loop has already ran. This happens because var i
is not blocked scoped, but rather function scoped
How would you fix this?
var arr = [1,2,3,4];
function closure(){
for(var i = 0; i < arr.length; i++){
setTimeout(function(){
console.log(i)
}, 100)
}
}
closure()
There are a couple of ways to fix this closure problem.
Using Let
var arr = [1,2,3,4];
function closure(){
for(let i = 0; i < arr.length; i++){
setTimeout(function(){
console.log(i)
}, 100)
}
}
closure()
This would be the quickest way because using let
allows you to use BLOCK SCOPING. This means that instead of using a var
which uses FUNCTION SCOPING, the let
is recreated (and uses the previous value) every time the for loop runs. That means that when setTimeout
is executed, the closure
value of i
is persisted in memory because it a new let
is created and incremented from the previous value
Using IIFE
var arr = [1, 2, 3, 4];
function closure() {
for (var i = 0; i < arr.length; i++) {
(function (item) {
setTimeout(function () {
console.log(item);
}, 100);
})(i);
}
}
closure();
And IIFE is immediately invoked, at the iteration during which it passes the current value of the i
so that (because of closures) the item
param is then able to be referenced when the callback function is called with setTimeout
Using `bind`
var arr = [1,2,3,4];
function closure(){
for(var i = 0; i < arr.length; i++){
setTimeout(function(item){
console.log(item)
}.bind(null, i), 100)
}
}
closure()
Using bind
is another way of passing and encapsulating a variable's content based on when it was called. So when setTimeout is invoked then it's "bounded" to what the variable i
was at the time it was called.
Resources
Last updated