在某种孤立的环境中表达式的JavaScript eval

时间:2016-02-12 17:20:01

标签: javascript eval sandbox

我有一系列指令,如下所示:

[
  {"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命名空间并冒着冲突的风险。

这是我到目前为止所拥有的:

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这样的相对较重的库插入到项目中就更容易了,并尝试使用它。

这与其他“沙盒JavaScript评估”问题略有不同,如:

  1. 我真的不需要正确的沙盒,我执行的代码足够可信,我只想将所有这些结果变量放在一个隔离的空间中(例如,轻松地对JSON.stringify进行操作稍后等)。

  2. 这个在浏览器中处理JavaScript引擎,而不是像node.js这样的独立引擎。

1 个答案:

答案 0 :(得分:0)

此问题的基础不是沙盒,而是如何在JavaScript中访问给定对象(例如a)的属性(即bmem,...)作为局部变量,即没有任何前缀,如this.amem.a

结果是解决方案是臭名昭着的with statement(就像eval一样,有些人经常"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}"