var funcs=[];
for(let i=0;i<3;i++){
 funcs[i]=function(){
  
  return i;
 }
 
}
alert(funcs[1]);
alert(funcs[1]());
function (){
  return i;
 }
The second one like this
1
But I don't konw why the funcs[1] can executed not reporting an error 'i is undefined';
                        
Because the function created within the loop closes over the lexical environment that's active when it was created. That lexical environment is (conceptually) an object, which contains locals defined within it (and some other things), including the
ivariable, in this case the one created for that specific iteration of the loop body (because of the very special wayfortreatsletdeclarations in its initializer). This is the concept of a "closure," one of the central technologies of JavaScript. Even when execution passes out of the scope a given lexical environment is associated with (a function returns, we move on to the next iteration of the loop, etc.), if anything still has a reference to that environment object, like all objects it lives on.Because of how
forhandlesletin its initializer, each entry infuncsgets its own lexical environment, and thus its own copy ofi.When you call one of those functions, a new environment object is created with its "outer" environment set to the environment attached to the function. When you reference
iwithin the function code, it looks first at the function's environment and, ifiisn't found there, it looks to the outer environment — where it finds it (in this case) and uses it.In a comment you've said
Exactly right. With
var,iwould be hoisted up to the environment object associated with the function theforloop is in (or the global one, if this is global code). So all of the functions createed in the loop share the samei, which by the time you're calling them has the value3.This is one of the essential differences between
let/constandvar:letandconsthave block scope, andforhas special handling forletin its initializer.Let's follow through these various environment objects as they get created. Assuming this code:
When we call
example, after theconst funcs = []but before theforloop starts, the current environment object is the one created for the call toexample, so we have something like this in memory (ignoring some details):+−−−−−−−−−−−−−−−−+ current env>−−−−−−−−−−−−−−−−−−−−−−−−−>| `example` Call | | Env Object | +−−−−−−−−−−−−−−−−+ | [[Outer]] |>−−−>(The env obj for when `example` was created.) | funcs |>−+ +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ +−>| (array) | +−−−−−−−−−−−+ | length: 0 | +−−−−−−−−−−−+Now, the
forloop starts: A new per-iteration environment object is created put in place as the "current" one, with the previous one as its "outer" environment. Anivariable is created within that new per-iteration environment object, and given the value0:+−−−−−−−−−−−−−−+ current env>−−>| Iteration 0 | | Env Object | +−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−+ | [[Outer]] |>−−−−−−−>| `example` Call | | i: 0 | | Env Object | +−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−+ | [[Outer]] |>−−−>(The env obj for when `example` was created.) | funcs |>−+ +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ +−>| (array) | +−−−−−−−−−−−+ | length: 0 | +−−−−−−−−−−−+During the loop iteration, we create a function and store it in
funcs. The function gets a reference to the current environment object, which it keeps as[[Environment]](this is an implementation thing, you won't actually find that if you look at the function, it's not accessible at the code level, just within the JavaScript engine):+−−−−−−−−−−−−−−+ current env>−+>| Iteration 0 | / | Env Object | +−−−−−−−−−−−−−−−−+ / +−−−−−−−−−−−−−−+ | `example` Call | + | [[Outer]] |>−−−−−−−>| Env Object | | | i: 0 | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−+ | [[Outer]] |>−−−>(The env obj for when `example` was created.) | | funcs |>−+ | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ | +−>| (array) | | +−−−−−−−−−−−+ | | length: 1 | +−−−−−−−−−−−−−−−−−+ | | 0 |>−−−−−>| Function 0 | | +−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−+ | | [[Environment]] |>−−−−−+ | +−−−−−−−−−−−−−−−−−+ | | | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+Now this is where the clever handling of
letinforinitializers works (and in fact, the clever handling ofletandconstwithin aforloop's body as well): A new environment object for the next iteration is created, and the value ofiis copied from theifor the previous iteration to theifor the next iteration. So we have:+−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−>| Iteration 0 | | | Env Object | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−+ | `example` Call | | | [[Outer]] |>−−−+−−−>| Env Object | | | i: 0 | / +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−+ + | [[Outer]] |>−−−>(The env obj for when `example` was created.) | | | funcs |>−−−+ | | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ | | +−−>| (array) | | +−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ | current env>−+>| Iteration 1 | | | length: 1 | +−−−−−−−−−−−−−−−−−+ | | Env Object | | | 0 |>−−−>| Function 0 | | +−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−+ | | [[Outer]] |>−+ | [[Environment]] |>−+ | | i: 0 | +−−−−−−−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+Then the
iin that new environment is incremented to1, and a new function is created and stored infuncs, giving us:+−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−>| Iteration 0 | | | Env Object | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−+ | `example` Call | | | [[Outer]] |>−−−+−−−>| Env Object | | | i: 0 | / +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−+ + | [[Outer]] |>−−−>(The env obj for when `example` was created.) | | | funcs |>−−−+ | | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ | | +−−>| (array) | | +−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ | current env>−+>| Iteration 1 | | | length: 2 | +−−−−−−−−−−−−−−−−−+ | / | Env Object | | | 0 |>−−−>| Function 0 | | / +−−−−−−−−−−−−−−+ | | 1 |>−+ +−−−−−−−−−−−−−−−−−+ | + | [[Outer]] |>−+ +−−−−−−−−−−−+ | | [[Environment]] |>−−−+ | | | i: 1 | | +−−−−−−−−−−−−−−−−−+ | | | +−−−−−−−−−−−−−−+ | | | | | +−−−−−−−−−−−−−−−−−+ | | | +−>| Function 1 | | | | +−−−−−−−−−−−−−−−−−+ | | | | [[Environment]] |>−+ | | | +−−−−−−−−−−−−−−−−−+ | | | | | | | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | | | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+Then at the end of that iteration, we do the whole thing again for the last iteration, and get:
+−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−>| Iteration 0 | | | Env Object | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−+ | `example` Call | | | [[Outer]] |>−−+−−+ −>| Env Object | | | i: 0 | / / +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−+ | | | [[Outer]] |>−−−>(The env obj for when `example` was created.) | | | | funcs |>−−−+ | | | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ | | | +−−>| (array) | | +−−−−−−−−−−−−−−+ | | +−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−>| Iteration 1 | | | | length: 3 | +−−−−−−−−−−−−−−−−−+ | | | Env Object | | | | 0 |>−−−−−>| Function 0 | | | +−−−−−−−−−−−−−−+ | | | 1 |>−−−+ +−−−−−−−−−−−−−−−−−+ | | | [[Outer]] |>−+ | | 2 |>−+ | | [[Environment]] |>−−−−−+ | | | i: 1 | | +−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−−−+ | | | +−−−−−−−−−−−−−−+ | | | | | | | | | +−−−−−−−−−−−−−−−−−+ | | | +−−−−−−−−−−−−−−+ | | +−>| Function 1 | | | | current env>−+>| Iteration 2 | | | +−−−−−−−−−−−−−−−−−+ | | | / | Env Object | | | | [[Environment]] |>−−−+ | | | + +−−−−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−−−+ | | | | | | [[Outer]] |>−−−+ | | | | | | | i: 2 | | +−−−−−−−−−−−−−−−−−+ | | | | | +−−−−−−−−−−−−−−+ +−−−>| Function 2 | | | | | | +−−−−−−−−−−−−−−−−−+ | | | | | | [[Environment]] |>−+ | | | | | +−−−−−−−−−−−−−−−−−+ | | | | | | | | | | | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | | | | | | | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | | | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+When we call
funcs[1](), an environment for the call is created and its[[Outer]]environment is set to the[[Environment]]of the function. So just before wereturn iin that function, we have (leaving out some details):+−−−−−−−−−−−−−−+ current env>−−>| Call to | | `funcs[1]()` | | Env Object | +−−−−−−−−−−−−−−+ | [[Outer]] |>−−+ +−−−−−−−−−−−−−−+ | | | +−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−−−−+ | `example` call | | +−−−>| Env Object | | | +−−−−−−−−−−−−−−−−+ | | | [[Outer]] |>−−−>(The env obj for when `example` was created.) | | | funcs |>−+ | | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ | | +−>| (array) | \ +−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ +−−−−−−−−−−−+−−−>| Iteraton 1 | | | length: 3 | +−−−−−−−−−−−−−−−−−+ | | Env Object | | | 0 |>−−−−−>| (function) | | +−−−−−−−−−−−−−−+ | | 1 |>−−−+ +−−−−−−−−−−−−−−−−−+ | | [[Outer]] |>−+ | 2 |>−+ | | [[Environment]] |>... | | i: 1 | +−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−+ | | | | | +−−−−−−−−−−−−−−−−−+ | | +−>| (function) | | | +−−−−−−−−−−−−−−−−−+ | | | [[Environment]] |>−−−−+ | | +−−−−−−−−−−−−−−−−−+ | | | | | | +−−−−−−−−−−−−−−−−−+ | | +−−−>| (function) | | | +−−−−−−−−−−−−−−−−−+ | | | [[Environment]] |>... | | +−−−−−−−−−−−−−−−−−+ | | | | | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+When the function looks up
i, it looks in the current environment object. Since it's not there, it looks to the[[Outer]]object. It finds it there, with the value1, so that's the value it uses.In contrast, if we use
vartheiis hoisted to the environment object for the call toexample(wherefuncsis), so after the loop we have this instead (note thatiis no longer on the per-iteration environments):+−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−−>| Iteration 0 | | | Env Object | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−+ | `example` Call | | | [[Outer]] |>−−+−−+−>| Env Object | | +−−−−−−−−−−−−−−+ / / +−−−−−−−−−−−−−−−−+ | | | | [[Outer]] |>−−−>(The env obj for when `example` was created.) | | | | i: 3 | | | | | funcs |>−−−+ | | | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ | | | +−−>| (array) | | +−−−−−−−−−−−−−−+ | | +−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−>| Iteration 1 | | | | length: 3 | +−−−−−−−−−−−−−−−−−+ | | | Env Object | | | | 0 |>−−−−−>| Function 0 | | | +−−−−−−−−−−−−−−+ | | | 1 |>−−−+ +−−−−−−−−−−−−−−−−−+ | | | [[Outer]] |>−+ | | 2 |>−+ | | [[Environment]] |>−−−−−+ | | +−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−−−+ | | | | | | | | | | | | +−−−−−−−−−−−−−−−−−+ | | | +−−−−−−−−−−−−−−+ | | +−>| Function 1 | | | | current env>−+>| Iteration 2 | | | +−−−−−−−−−−−−−−−−−+ | | | / | Env Object | | | | [[Environment]] |>−−−+ | | | + +−−−−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−−−+ | | | | | | [[Outer]] |>−−−+ | | | | | | +−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−−+ | | | | | +−−−>| Function 2 | | | | | | +−−−−−−−−−−−−−−−−−+ | | | | | | [[Environment]] |>−+ | | | | | +−−−−−−−−−−−−−−−−−+ | | | | | | | | | | | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | | | | | | | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | | | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+Which means when we call
funcs[1](), a new environment is created for it, its[[Outer]]is set to the function's[[Environment]], and just beforereturn iwe have:+−−−−−−−−−−−−−−+ current env>−−>| Call to | | `funcs[1]()` | | Env Object | +−−−−−−−−−−−−−−+ | [[Outer]] |>−−+ +−−−−−−−−−−−−−−+ | | | +−−−−−−−−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−+ | | `example` call | | +−−−>| Env Object | | | +−−−−−−−−−−−−−−−−+ | | | [[Outer]] |>−−−>(The env obj for when `example` was created.) | | | i: 3 | | | | funcs |>−+ | | +−−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ | | +−>| (array) | \ +−−−−−−−−−−−−−−+ | +−−−−−−−−−−−+ +−−−−−−−−−−−+−−−>| Iteration 1 | | | length: 3 | +−−−−−−−−−−−−−−−−−+ | | Env Object | | | 0 |>−−−−−>| (function) | | +−−−−−−−−−−−−−−+>−+ | 1 |>−−−+ +−−−−−−−−−−−−−−−−−+ | | [[Outer]] | | 2 |>−+ | | [[Environment]] |>... | +−−−−−−−−−−−−−−+ +−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−−−+ | | | | | | +−−−−−−−−−−−−−−−−−+ | | +−>| (function) | | | +−−−−−−−−−−−−−−−−−+ | | | [[Environment]] |>−−−−+ | | +−−−−−−−−−−−−−−−−−+ | | | | | | +−−−−−−−−−−−−−−−−−+ | | +−−−>| (function) | | | +−−−−−−−−−−−−−−−−−+ | | | [[Environment]] |>... | | +−−−−−−−−−−−−−−−−−+ | | | | | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+So when the function looks up
i, it doesn't find it in the current environment, and it doesn't find it in the first[[Outer]]environment, but it does find it in the second[[Outer]]environment, with the value3, so that's the value it uses.