Explanation of `let` and block scoping with for loops

后端 未结 3 1099
旧巷少年郎
旧巷少年郎 2020-11-22 01:42

I understand that let prevents duplicate declarations which is nice.

let x;
let x; // error!

Variables declared with let

3条回答
  •  抹茶落季
    2020-11-22 01:53

    let introduces block scoping and equivalent binding, much like functions create a scope with closure. I believe the relevant section of the spec is 13.2.1, where the note mentions that let declarations are part of a LexicalBinding and both live within a Lexical Environment. Section 13.2.2 states that var declarations are attached to a VariableEnvironment, rather than a LexicalBinding.

    The MDN explanation supports this as well, stating that:

    It works by binding zero or more variables in the lexical scope of a single block of code

    suggesting that the variables are bound to the block, which varies each iteration requiring a new LexicalBinding (I believe, not 100% on that point), rather than the surrounding Lexical Environment or VariableEnvironment which would be constant for the duration of the call.

    In short, when using let, the closure is at the loop body and the variable is different each time, so it must be captured again. When using var, the variable is at the surrounding function, so there is no requirement to reclose and the same reference is passed to each iteration.

    Adapting your example to run in the browser:

    // prints '10' 10 times
    for (var i = 0; i < 10; i++) {
      setTimeout(_ => console.log('var', i), 0);
    }
    
    // prints '0' through '9'
    for (let i = 0; i < 10; i++) {
      setTimeout(_ => console.log('let', i), 0);
    }
    

    certainly shows the latter printing each value. If you look at how Babel transpiles this, it produces:

    for (var i = 0; i < 10; i++) {
      setTimeout(function(_) {
        return console.log(i);
      }, 0);
    }
    
    var _loop = function(_i) {
      setTimeout(function(_) {
        return console.log(_i);
      }, 0);
    };
    
    // prints '0' through '9'
    for (var _i = 0; _i < 10; _i++) {
      _loop(_i);
    }

    Assuming that Babel is fairly conformant, that matches up with my interpretation of the spec.

提交回复
热议问题