There is the following code
function fn1 () {
const a = 1;
const b = 2;
const c = 3;
function fn2() {
console.log("xx");
}
function fn3() {
console.log(a);
console.log(c);
}
return fn2;
}
const clo = fn1();
console.dir(clo);
When I was run this code in Chrome Console, I got this:
I know fn3 references the variable of fn1, but I just return the fn2, why there is a closure in fn2 [[Scopes]]
?
Hope that people who know this reason to give some advice! thank you.
CodePudding user response:
Both fn2
and fn3
are created within fn1
, so both are closures over (have a reference to) the lexical environment object created for the call to fn1
. (The lexical environment object is what holds the bindings for a
, b
, c
, and a few other things.) That's true whether they use that link (like fn3
does, by accessing fn1
's local variables) or not (fn2
).
Some JavaScript engines have experimented with optimizing that away when possible: removing a function's link to the environment where it was created (linking it directly to the outer environment instead). IIRC, V8 (in Chrome) did experiment with doing that, but found that in most cases the runtime cost of doing that analysis was more expensive than just letting the closure remain, and so didn't carry that work forward when they replaced the internals of the engine a few years back.
Separately, some engines have experimented with optimizing the content of closures — removing the bindings from the lexical environment object that aren't used by any of the functions closing over it. From your screenshot, it looks like V8 does still do that part, at least in trivial cases like that one, since only the bindings that fn3
uses are listed (a
and c
, not b
). At a specification level, all of those bindings would be retained (not that we could tell in our code), but engines are free to optimize where the optimization doesn't lead to out-of-specification behavior.
CodePudding user response:
When you are returning fn2
a closure is created that makes all the available variables in the outer scope available.
JS doesn't check if you actually use those variables, they are added to the closure none the less.