Closures with Loops
Video
JavaScript Notes
JavaScript
let counter = 0;
let names = ['Bob','Tina','Gene','Mort','Louise','Ollie'];
// Note: a closure gives you access to an outer function’s scope from an inner function
//closure so we are good
names.forEach( looper );
//closure so we are good
for(let i=0; i<names.length; i++){
looper(names[i], i, names);
}
//closure so we are good
for(var i=0; i<names.length; i++){
looper(names[i], i, names);
}
function looper(item, index, arr){
setTimeout(function(){ console.log(index, item)}, 1000 * index);
//this function creates the closure
if(counter<6)
console.log('forEach', index, item);
else if(counter>5 && counter < 12)
console.log('for let', index, item);
else
console.log('for var', index, item);
counter++;
}
//no closure. Sad face.
for(var i=0; i<names.length; i++){
setTimeout(function(){ console.log('SAD', i, names[i])}, 1000 * i);
}
// this bit fails, as var 'i' is globally scoped, so doesn't get destroyed after the for loop finishes
// so when the first setTimeout runs, 'i' = 6, which causes the function to fail
// using let, instead of var, would locally scope 'i', and automatically create a closure (wraps the setTimeout function in an IIFE, causing immediate attachment of 'i' each time setTimeout is run)
// alternative workarounds would be to rework the code to create a closure - as shown below
//rework to create closure
for(var i=0; i<names.length; i++){
//version one - works - i.e. pass the variable, i, into the function as a parameter of the function
setTimeout( (function(num){
console.log('ONE', num, this[num])}).bind(names, i)
, 1000 * i);
//version two - works - i.e. pass the variable, i, into the function as a parameter of the function
setTimeout( (function(num){
console.log('TWO', num, names[num])
}), 1000 * i, i);
//the key is to pass a copy of i into the function to be used later... the closure
}
Feedback
Submit and view feedback