JavaScript 在有些孤立的环境中对表达式进行评估
JavaScript eval for expressions in somewhat isolated environment
我有一组指令,如下所示:
[
{"name": "a", "expr": "1"},
{"name": "b", "expr": "4"},
{"name": "c", "expr": "a * b + 100"},
{"name": "a", "expr": "a - 5"}
]
我想在浏览器中使用 JavaScript 引擎 运行 执行它们,然后访问结果。
显然,第一次尝试只是
eval(inst.name + " = " + inst.expr);
事实上,它有效,但它会污染全局 window
名称space 并有冲突的风险。
这是我目前的情况:
var Memory = (function() {
function Memory() {}
Memory.prototype.evalExpr = function(expr) {
return eval(expr);
};
return Memory;
})();
var mem = new Memory();
然后每条指令inst
执行使用:
mem[inst.name] = mem.evalExpr(inst.expr);
这是半成品,但我必须更改所有指令以在所有变量名称前加上 this.
,即:
[
{"name": "a", "expr": "1"},
{"name": "b", "expr": "4"},
{"name": "c", "expr": "this.a * this.b + 100"},
{"name": "a", "expr": "this.a - 5"}
]
有没有什么快速方法可以以不需要在变量名前加上 this.
的方式对对象进行读取操作?正确地动态修改表达式需要构建一个成熟的表达式解析器——换句话说,将一个相对重量级的库(如 jison 插入项目)并尝试使用它会更容易。
这与其他 "sandboxed JavaScript eval" 问题有些不同,如:
我真的不需要适当的沙箱,我执行的代码足够可信,我只想将所有这些结果变量放在一个隔离的 space 中(例如,做JSON.stringify
以后随便就可以了,等等)。
这个处理浏览器中的 JavaScript 引擎,而不是像 node.js.
这样的独立引擎
这个问题的基石不是沙盒,而是如何访问给定对象(比如 mem
)的属性(即 a
、b
、...)在 JavaScript 中作为局部变量,即没有任何前缀,如 this.a
或 mem.a
.
结果证明解决方案是某些人臭名昭著的 with
statement (just as eval
, it is also frequently "considered harmful")。然而,在这种情况下,它完美地完成了工作:可以用它动态地评估任意表达式:
function VM() {
this.mem = {};
}
VM.prototype.varSet = function(varName, expr) {
var _t;
with (this.mem) { _t = eval(expr) };
this.mem[varName] = _t;
};
vm = new VM()
因此,很容易执行指令:
insts.forEach(function(inst) {
vm.varSet(inst.name, inst.expr);
});
获得个别结果:
vm.mem.a // => -4
并将所有结果作为适当的纯 JavaScript 对象组合在一起,例如,导出为 JSON 字符串:
JSON.stringify(vm.mem) // => "{\"a\":-4,\"b\":4,\"c\":104}"
我有一组指令,如下所示:
[
{"name": "a", "expr": "1"},
{"name": "b", "expr": "4"},
{"name": "c", "expr": "a * b + 100"},
{"name": "a", "expr": "a - 5"}
]
我想在浏览器中使用 JavaScript 引擎 运行 执行它们,然后访问结果。
显然,第一次尝试只是
eval(inst.name + " = " + inst.expr);
事实上,它有效,但它会污染全局 window
名称space 并有冲突的风险。
这是我目前的情况:
var Memory = (function() {
function Memory() {}
Memory.prototype.evalExpr = function(expr) {
return eval(expr);
};
return Memory;
})();
var mem = new Memory();
然后每条指令inst
执行使用:
mem[inst.name] = mem.evalExpr(inst.expr);
这是半成品,但我必须更改所有指令以在所有变量名称前加上 this.
,即:
[
{"name": "a", "expr": "1"},
{"name": "b", "expr": "4"},
{"name": "c", "expr": "this.a * this.b + 100"},
{"name": "a", "expr": "this.a - 5"}
]
有没有什么快速方法可以以不需要在变量名前加上 this.
的方式对对象进行读取操作?正确地动态修改表达式需要构建一个成熟的表达式解析器——换句话说,将一个相对重量级的库(如 jison 插入项目)并尝试使用它会更容易。
这与其他 "sandboxed JavaScript eval" 问题有些不同,如:
我真的不需要适当的沙箱,我执行的代码足够可信,我只想将所有这些结果变量放在一个隔离的 space 中(例如,做
JSON.stringify
以后随便就可以了,等等)。这个处理浏览器中的 JavaScript 引擎,而不是像 node.js.
这样的独立引擎
这个问题的基石不是沙盒,而是如何访问给定对象(比如 mem
)的属性(即 a
、b
、...)在 JavaScript 中作为局部变量,即没有任何前缀,如 this.a
或 mem.a
.
结果证明解决方案是某些人臭名昭著的 with
statement (just as eval
, it is also frequently "considered harmful")。然而,在这种情况下,它完美地完成了工作:可以用它动态地评估任意表达式:
function VM() {
this.mem = {};
}
VM.prototype.varSet = function(varName, expr) {
var _t;
with (this.mem) { _t = eval(expr) };
this.mem[varName] = _t;
};
vm = new VM()
因此,很容易执行指令:
insts.forEach(function(inst) {
vm.varSet(inst.name, inst.expr);
});
获得个别结果:
vm.mem.a // => -4
并将所有结果作为适当的纯 JavaScript 对象组合在一起,例如,导出为 JSON 字符串:
JSON.stringify(vm.mem) // => "{\"a\":-4,\"b\":4,\"c\":104}"