JavaScript 评估,用于在某种隔离环境中的表达式

JavaScript eval for expressions in somewhat isolated environment

本文关键字:环境 隔离 表达式 评估 用于 JavaScript      更新时间:2023-09-26

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

[
  {"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 这样的相对重量级的库插入到 project 中会更容易(并尝试接受它。

这与其他"沙盒 JavaScript 评估"问题有些不同,因为:

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

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

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

结果发现,解决方案是臭名昭著的with声明(就像eval一样,它也经常被某些人"认为有害"(。然而,在这种确切的情况下,它可以完美地完成工作:可以使用它动态地计算任意表达式:

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}"