Your current code is correct because that is how scopes work - anything from an outer scope is visible within an inner one.
The only reason why it would not work is if the function was serialised and then deserialised - that completely removes all scope information:
{ //different scope here
const foo = 1;
const result = functionThatExpectsCallback('genericString', (data) => {
// do stuff with foo here, e.g.
console.log("foo is:", typeof foo);
const bar = foo + data.num;
return bar;
});
console.log(result);
}
//dummy implementation that serialises and deserialises a function to run it:
function functionThatExpectsCallback(arg, callback) {
return runFromString(callback.toString());
}
function runFromString(strFunc) {
const fn = eval(`(${strFunc})`);
return fn({ num: 2 });
}
The first way to solve this is by checking the documentation of whatever library is used - it might provide a way to also send along extra arguments.
If that is not an option, then you would need to do it the dirty way and generate the function from string. You can use the Function
constructor to do that
{ //different scope here
const foo = 1;
const generatedFunction = new Function("data", `
// do stuff with foo here, e.g.
const bar = ${foo} + data.num;
return bar;
`);
const result = functionThatExpectsCallback('genericString', generatedFunction);
console.log(result);
}
function functionThatExpectsCallback(arg, callback) {
return runFromString(callback.toString());
}
function runFromString(strFunc) {
const fn = eval(`(${strFunc})`);
return fn({ num: 41 });
}
You have to be very careful because it is easy to introduce minor mistakes when generating a function from string and you can end up with invalid code. For example, if foo
was a string foo = "hello"
then the generated code would be const bar = hello + data.num;
which is invalid because hello
would be a variable which was never defined, instead of the string literal "hello"
.