Block Binding using Javascript – Functions in Loops

I wanted to go take a deep dive into using Javascript’s ‘let’ to declare variables and data objects. I’ve briefly covered ‘let’ on a previous post, but just barely scratched the surface on its features – especially using let as functions in loops. Yeah, I know that was a mouthful.

I found my self using this method once before – for getting around an API quota limit. But even if you haven’t used this method before to get around the scoping issue, these examples and comparisons (ES6) provide tidbits of useful concepts that may aid you as a developer when tackling complex data processing and manipulation.

The first script below is problem for developers when using var, what we capture is the same value each time. This is because the variable ‘i’ references the last value once the loop completes. In this case, the forEach() loop outputs 10, ten times. We don’t want that.

// Problem
var cups = [];

for (var i = 0; i < 10; i++) {
  
  cups.push(function() {
     console.log(i);

  });

}

cups.forEach(function(cup) {

   cup();

});  // outputs the number 10
ten times

See, below solution to get around the mentioned issue. Now this is what we want. What’s different here? Well, we wrap the entire function in an Immediately Invoked Function Expression (IIFE). This is a common solution to creating a new execution context, thus preserving generated values within the loop.

// Solution
var cups = [];

for (var i = 0; i < 10; i++) {

  cups.push((function(value) {

     return function() {
       console.log(value);

     }
  }(i)));

}

cups.forEach(function(cup) {

   cup();

}); // outputs 0 to 9

Alright, what about ES6?

Well, with ES6 we don’t need to wrap our function inside of an IIFE. We let the power of ‘let’ do it’s magic. Each time the loop iterates and because ‘let’ is blocked scoped – creates a new value of ‘i’.

Voila, there we have it. See below how ‘let’ can handle the same process in one fell swoop.

// For Arrays
let cups = [];

for (let i = 0; i < 10; i++) {
    cups.push(function() {
        console.log(i);
    });
}

cups.forEach(function(cup) {

    cup();     

}); // // outputs 0 to 9

And in case you’re wondering how to utilize ‘let’ for iterating over objects, we got you covered.

// For Objects
let cups = [];

let scoops = {
        chocolate: 3,
        vanilla: 4,
        'chocolate chip': 5
    };

for (let scoop in scoops) {
    
    cups.push(function() {
        console.log(scoop);
    });

}

cups.forEach(function(cup) {
    
    cup();

}); // outputs chocolate, vanilla, chocolate chip

I think by comparing the non ES6 vs the ES6 way, we can easily contrast the effectiveness of ‘let’. This allows for much cleaner and concise code. But just in case you run into the non ES6 way using ‘var’ – you know why an IIFE is used to retain values within the scope execution context.