在vm脚本上下文中传递函数

3

假设我有一个如下所示的库模块:

module.exports = {
    increment: function() {
         count++;
    }
}

我希望在一个动态生成的脚本中使用它,该脚本看起来像这样:

(function() { lib.increment(); })();

通过在沙盒中传递它:

var sandbox = {
    count: 1
    lib: require('./lib')
}
var script = new vm.Script('(function() { lib.increment() })();');
script.runInNewContext(sandbox);

我遇到的明显问题是,一方面我不能要求“lib”,因为“lib.js”中未定义“count”;另一方面,如果我在“lib.js”文件的导出之前定义 var count ,则这个新的 count 变量将受到影响而不是沙盒中的变量。
以下是我想要遵守的限制:
  • 使用vm而不是eval()或在生成的文件上进行require()
  • 在外部文件中定义“lib”
  • 不修改自动生成的脚本,因此不使用 lib.increment.apply(context)或类似方法
迄今为止,我找到的唯一解决方案是将“lib”函数作为字符串在生成的脚本中加以前缀,或者直接在“sandbox”对象上定义它们,但我认为后者不是一个理想的选择。
似乎没有办法在require调用中传递变量上下文。

为什么不直接将exports作为一个返回带有get/set和increment方法的对象的函数呢? - Jed Fox
或者你可以将导出设置为一个接受上下文参数的函数。然后你可以执行 require('./lib')({ count: 1 }),它会返回一个带有 increment 函数的对象。 - Mike Cluck
1
@MikeC 看到了吗,这就是为什么你永远不应该害怕提问,那是一个相当好的建议! - Pierre Arlaud
你想做的是 global.count++ 吗? - Bergi
@Bergi你说的“global”是什么意思?我需要更改在沙盒中传递的上下文。 - Pierre Arlaud
@MikeC 我可能会采用你的想法,你可以发布一个答案,这样我就可以接受它;-) - Pierre Arlaud
1个回答

5

实现这一点的一种方法是使你的lib模块成为一个函数,该函数接受上下文,然后返回正确的接口。

lib.js

module.exports = function(context) {
  var count = context.count;
  return {
    increment: function() {
      count++;
    }
  };
};

main.js

var sandbox = {
  count: 1
};
sandbox.lib = require('./lib')(sandbox);
var script = new vm.Script('(function() { lib.increment() })();');
script.runInNewContext(sandbox);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接