is there any way I can execute eval() on a specific scope (but NOT global)?
for example, the following code doesn\'t work (a is undefined on the sec
The poor man's method:
If your scope is not too dynamic, just a couple of static and read-only declarations, simply put it in a string and concatenate with the string what you wanna execute like this:
const scopeAll = `
const myFunc = (a, b) => a + b + s;
`
const scope1 = `
${scopeAll}
const s = 'c';
`
const scope2 = `
${scopeAll}
const s = 'd';
`
const myStringToExecute = `
myFunc('a', 'b')
`
console.log(eval(scope1 + myStringToExecute));
console.log(eval(scope2 + myStringToExecute));
The approach here was to allow a context object to parameterize the evaluation of the expression.
First a function is created using the Function() constructor that accepts every key of the context as well as the expression to evaluate; the body returns the evaluated expression. Then that function is called with all of the values of the context and the expression to evaluate.
function scopedEval(context, expr) {
const evaluator = Function.apply(null, [...Object.keys(context), 'expr', "return eval(expr)"]);
return evaluator.apply(null, [...Object.values(context), expr]);
}
// Usage
const context = {a: 1, b: 2, c: {d: 3}};
scopedEval(context, "a+b+c.d"); // 6
By using Function.prototype.apply the number of arguments and the names don't need to be known beforehand. Because the arguments are scoped to the evaluator
function they are directly accessible from the expression (instead of requiring this.a
).
This is the simplest way I found to do that, but it doesn't use eval.
function execInContext(code, context)
{
return Function(...Object.keys(context), 'return '+ code (...Object.values(context));
}
Here we create a Function
object. The Function
constructor accepts an array of parameters, the last one is the code to be executed by the function and all others are argument names for the function. What we're doing is creating a function that has arguments with the same names as the fields in the context
object and then calling this function with the values of the fields in context
. So if you call
execInContext('myVar', {myVar: 'hi!'});
it's the same as
((myVar) => { return myVar; })('hi!');
and the result will be hi!