I tried the following code
let let_arr = [];
for (let i = 0; i < 4; i++) {
let_arr[i] = () => {
return {
let_i: i
}
};
}
console.log(let_arr);
and I found the block key exists when we use let in for loop.
[ƒ, ƒ, ƒ, ƒ]
0: () => {…}
arguments: (...)
caller: (...)
length: 0
name: ""__proto__: ƒ ()
[[FunctionLocation]]: iif.js:26
[[Scopes]]: Scopes[3]
0: Block {i: 0}
1: Script {let_arr: Array(4), var_arr: Array(4)}
2: Global {window: Window, self: Window, document: document, name: "", location: Location, …}
While when using var
for (var i = 0; i < 4; i++)
block element is missing.
[[Scopes]]: Scopes[2]
0: Script {let_arr: Array(4), var_arr: Array(4)}
1: Global {window: Window, self: Window, document: document, name: "", location: Location, …}
Javascript functions are actually closures, that is, when you save a function somewhere, not only its code is retained, but also all variables available at the creation time. Variables are stored in dictionaries called scopes, which can be nested in each other ("scope chain").
In order to conserve memory, the engine only retains scopes that are actually used in the function. If a scope does not contain let/const
, it is considered unused and omitted. If a scope does contain let
, but that variable is not used in the function, it's also omitted. Otherwise the scope is retained and attached to the closure.
A couple of illustrations:
var f
{
var a
f = () => a // Global
}
console.dir(f)
//
{
let a
f = () => a
}
console.dir(f) // Block a + Global
//
{
let a
{
let b
{
let c
f = () => b
}
}
}
console.dir(f) // Block b + Global
//
{
let a
{
let b
{
let c
f = () => eval("b")
}
}
}
console.dir(f) // 'eval' retains everything