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" 问题有些不同,如:

  1. 我真的不需要适当的沙箱,我执行的代码足够可信,我只想将所有这些结果变量放在一个隔离的 space 中(例如,做JSON.stringify以后随便就可以了,等等)。

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

  3. 这样的独立引擎

这个问题的基石不是沙盒,而是如何访问给定对象(比如 mem)的属性(即 ab、...)在 JavaScript 中作为局部变量,即没有任何前缀,如 this.amem.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}"