Closure values get lost in a function passed as a callback to another function defined by new Function() method.
Code
How can the function baz() be fixed to access the closure values in the callback?
Note: The function foo() cannot be modified.
const foo = () => {
const b = 2;
return (a) => {
return a b; // unable to access `b` here
};
};
const bar = (a = 1, callback = foo()) => callback(a);
const baz = new Function(["a = 1", `callback = ${foo()}`], "return callback(a)");
console.log(bar(1)); // works fine and prints 3
console.log(baz(1)); // throws Uncaught ReferenceError: b is not defined
CodePudding user response:
Don't use string interpolation with a function. What is happening can be seen here:
const foo = () => {
const b = 2;
return (a) => a b;
};
console.log(new Function(["a = 1", `callback = ${foo()}`], "return callback(a)"))
The function (a) => a b gets converted to a string, which is then put in the source code of the new function. Yes, this looses the closure - it looses the entire function object.
Instead, just write
const foo = () => {
const b = 2;
return (a) => a b;
};
const bar = function(a = 1, callback = foo()) { return callback(a); };
const baz = new Function(["a = 1", "callback = foo()"], "return callback(a)");
console.log(bar(1));
console.log(baz(1));
console.log(bar);
console.log(baz);
As you can see from the logged functions, their code is now equivalent - and since everything in the demo snippet is global, they also work the same.
It's a bit different when foo (or anything else you want to access from the function code string) is defined in a local scope. In that case, you'll need to use a trick like this to explicitly make the value available to the dynamically generated code.
CodePudding user response:
I believe that Function constructors only execute within the global scope and do no create closures. This answer may help you:
