我正在尝试在“隔离的”上下文中运行受信任的 JS代码。
基本上想出了这种方法:
function limitedEval(src, context) {
return (function() {
with(this) {
return eval(src)
}
}).call(context)
}
这很好用,但是当脚本使用
var
关键字时,它存储在执行上下文中,而不是with语句中提供的上下文中(我理解这是设计使然)。因此,例如,以下代码不起作用:var ctx = {};
limitedEval('var foo = "hello"', ctx);
limitedEval('alert(foo)', ctx); // error: foo is undefined
我希望能够多次调用limitedEval()并重用上下文。那可能吗?
最佳答案
这似乎是一个非常有趣的问题。代码的问题在于,每次执行limitedEval
时,都会生成新函数。这意味着您使用var
关键字创建的任何变量都将仅存在于该函数的上下文中。您真正需要的是每个上下文具有1个函数并重用该函数的上下文。最明显的方法是使用generators。生成器本质上是可以暂停然后重新启动的功能。
// IIFE to store gen_name
var limitedEval = function() {
// Symbol for generator property so we don't pollute `ctx` namespace
var gen_name = Symbol();
return function limitedEval(src, context) {
if(!(gen_name in context)) {
// Generator that will run eval and pause til getting the next source code
var generator = function * () {
with(this) {
while(true) {
yield eval( yield );
}
}
};
context[gen_name] = generator.call(context);
// Initially, we need to execute code until reaching the first `yield`
context[gen_name].next();
}
// First, send the source to the `eval`
context[gen_name].next( src );
// Second, get the `eval` result
return context[gen_name].next().value;
};
}();
现在你可以打电话
var ctx = {};
limitedEval('var foo = "hello"', ctx);
limitedEval('alert(foo);', ctx);
现在,每个
limitedEval
调用都将重用将在提供的ctx
对象上找到的任何生成器函数。如果该函数不存在,它将创建它并将其放在ctx
对象上。因为现在每个ctx
只有一个函数,所以在使用var
关键字创建变量时,它将重用该函数的上下文。注意:您将无法通过ctx
对象查找这些变量,因为它们仅存在于函数的上下文中。我不确定是否不使用生成器也可以达到相同的结果。
编辑:其他人提出了很好的建议,所以我用
Symbol
替换了随机生成的属性,并做了with(this)
而不是with(context)
关于javascript - 在有限的上下文中运行JS代码,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43989742/