18

Trying to print series of numbers inside for loop using closures and with let:

Consider the following example:

  for(var i=1; i<10; i++){      
      setTimeout(function(){
        document.write(i);
      }, 1000);
  }

Output is:

101010101010101010

With Closures:

  for(var i=1; i<10; i++){    
    (function(x){      
      setTimeout(function(){
        document.write(x);
      }, 1000);      
    })(i);
  }

Output is:

123456789

Without closure, just using ES6 let:

 for(let i=1; i<10; i++){      
      setTimeout(function(){
        document.write(i);
      }, 1000);
  }

Output is:

123456789

Trying to understand if we still need closures using IIFE blocks moving towards ES6?

Any good example if we really need closures with ES6?

Mithun Shreevatsa
  • 3,588
  • 9
  • 50
  • 95
  • 2
    It's still a closure. The difference is that the scope is provided by the block, not the IIFE. – Bergi Jan 27 '17 at 11:12
  • so, then my question would be do we need IIFE blocks then rather than closure ;) :P – Mithun Shreevatsa Jan 27 '17 at 11:15
  • [JavaScript closure inside loops – simple practical example](http://stackoverflow.com/q/750486/1529630) – Oriol Jan 27 '17 at 11:23
  • I don't exactly understand what you are asking, doesn't your question already show that you don't need an IIFE when using `let`? – Oriol Jan 27 '17 at 11:24
  • 1
    In that case, it sounds like a duplicate of [Will const and let make the IIFE pattern unnecessary?](http://stackoverflow.com/q/33534485/1048572) – Bergi Jan 27 '17 at 12:05
  • This is Gold. Am saving it for future reference. – sg28 Apr 15 '19 at 02:36

4 Answers4

7

Here's a good explanation by Kleo Petrov -

Do ES6 Modules make the case of IIFEs obsolete?

IIFE was one of the most used patterns in the ES5, as functions were the only way to declare a scoped block of code. In ES6, instead of using IIFE, we can use modules:

// myModule.js

let counter = 0;

export function increment() {
    counter++;
}    

// logic.js

import {increment} from 'myModule.js';

increment();

The only case, where you may want to use an IIFE in ES6, is with an immediately-invoked arrow functions, that requires more than a single expression, for example:

const SENTENCE = 'Hello world, how are you?';
const REVERSE = (() => {
    const array  = [...SENTENCE];
    array.reverse();
    return array.join('');
})();
Noam Manos
  • 15,216
  • 3
  • 86
  • 85
5

One simple example of using closures, that I could remember, is a counter:

function makeCounter() {
  let currentCount = 1;

  return function() { 
    return currentCount++;
  };
}

let counter = makeCounter(); 


console.log( counter() ); // 1
console.log( counter() ); // 2
console.log( counter() ); // 3
Evgeny Kuznetsov
  • 2,132
  • 2
  • 17
  • 27
5

let binds names in the block scope for the variables declared with it. You can read the semantics in the standard document.

If you have let, use it. Otherwise use IIFE or rewrite the code to avoid needing either.

Dan D.
  • 73,243
  • 15
  • 104
  • 123
1

This particular use case when you want to use the value of a variable which is reassigned in a loop at each iteration is indeed simplified with the new Es6 block scoping.

There is a very good review of the behavior of this in the latest N. Zachas book available on github (the whole book is a very good read and you should probably buy it if you intend to use it as a main reference).

As for your example using the new syntax is probably the new best practice because it results in the expected behavior, whereas the old for(var i = 0; i < length; i++){} syntax was confusing.

Keep in mind however that you will probably want to transpile your code to es5 using either Babel or Tracer. In this case, the way those tools use to simulate block scoping is by using closures. So you probably should understand the pattern anyway for sake of completion and debugging purposes.

Example of transpilation from the example in the book here

adz5A
  • 2,012
  • 9
  • 10