3

So, trying to learn a bit about ES6, I came over this link, http://es6-features.org/#BlockScopedVariables

// ES6

let callbacks = []
for (let i = 0; i <= 2; i++) {
    callbacks[i] = function () { return i * 2 }
}
callbacks[0]() === 0
callbacks[1]() === 2
callbacks[2]() === 4

// ES5

var callbacks = [];
for (var i = 0; i <= 2; i++) {
    (function (i) {
        callbacks[i] = function() { return i * 2; };
    })(i);
}
callbacks[0]() === 0;
callbacks[1]() === 2;
callbacks[2]() === 4;

May I know why in ES5 Method we are using an immediate function to return the i*2 value?

But in ES6, just assigning the value in loop works?

Basically,

  1. Want to Know why this difference occurs?
  2. How does that loop is getting executed?
  3. I find the difference is due to "block scope (let) & global scope (var)", but want to know more about the execution/runtime point?
  4. So we don't want to use immediate function for saving the current state of variable in ES6?
deceze
  • 510,633
  • 85
  • 743
  • 889
Sathish
  • 2,056
  • 3
  • 26
  • 40
  • possible duplicate of [Javascript - "let" keyword vs "var" keyword](http://stackoverflow.com/questions/762011/javascript-let-keyword-vs-var-keyword) – TaoPR Jul 01 '15 at 10:01
  • @TaoP.R. If it's duplicated, please explain how that loop works? – Sathish Jul 01 '15 at 10:03
  • see also [Explanation of `let` and block scoping with for loops](http://stackoverflow.com/a/30900289/1048572) (not sure if duplicate) – Bergi Jul 01 '15 at 17:17

1 Answers1

4

As you say, the difference is between using let which creates a block-scoped variable vs using var which creates an execution context scoped variable - not just global, but the executing function's scope.

// ES6
var callbacks = [];
for (let i = 0; i <= 2; i++) {
    // A new LexicalEnvironment is established here, where i only survives
    // the duration of this 'for' statement
    // So we can safely say that when function() is called, `i` will have
    // the value we assign to it here
    callbacks[i] = function () { return i * 2 }
}

However, in ES5...

// LexicalEnvironment is established here and `i` is declared
var callbacks = [];
for (var i = 0; i <= 2; i++) {
    callbacks[i] = function() { return i * 2; };
}
// `i` is still available now and its value is currently 2
// So when you execute `callbacks[2]()` the LexicalEnvironment where `i` was set
// is the one where i === 3
callbacks[0]() // 6
callbacks[1]() // 6
callbacks[2]() // 6

Now, using an IIFE in ES5...

var callbacks = [];
for (var i = 0; i <= 2; i++) {
    // Much like using let, by declaring an IIFE here, we are telling the engine
    // to create a new LexicalEnvironment to store the current value of i
    (function (i) {
        callbacks[i] = function() { return i * 2; };
    })(i);
}
marcel
  • 2,967
  • 1
  • 16
  • 25
CodingIntrigue
  • 75,930
  • 30
  • 170
  • 176