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
    }