The following Javascript program:
function f() {
function g() { console.log(x); }
let x = 0;
g(); // prints 0
x = 1;
g(); // prints 1
return g;
}
let g = f();
g(); // prints 1
outputs:
0
1
1
So it seems that g first captures x by reference (since inside f, g() prints 0 then 1 when x is rebound), which means that g closure environment looks something like {'x': x}, and then by value (since outside f, g() prints 1 when x goes out of context at the end of f body), which means that g closure environment looks something like {'x': 1}.
I am trying to relate this behaviour with C++ lambdas which provide capture by reference and by value, but contrary to Javascript, do not allow a capture by reference to outlives the scope of the reference by turning into a capture by value (instead, calling the lambda becomes undefined behaviour).
Is it a correct interpretation of Javascript captures?
If that interpretation is correct, that would explain clearly how captures of block scope variables (let) work in for loops:
let l = [];
for (let x = 0; x < 3; ++x) {
l.push(function () { console.log(x); });
}
l[0](); // prints 0
l[1](); // prints 1
l[2](); // prints 2