NodeJS:runInNewContext和instanceof

时间:2012-11-07 15:40:01

标签: node.js instanceof

我有一个类似这样的脚本:

var context = {}
vm.runInNewContext("var someFunc = function() {}", context);
console.log(typeof context.someFunc); //function
console.log(context.someFunc instanceof Function); //false

我理解为什么第4行返回false:在新上下文中有一个新的Function对象,它不等于外部上下文中的Function对象。因此,context.someFunc不是该外Function个对象的实例。

但是,context.someFunc函数由使用instanceof Function的第三方库使用。由于context.someFunc是一个函数,但不是该上下文中Function的实例,因此第三方不会将其视为函数,因此它会崩溃。我尝试使用以下上下文:

var context = {
    "Function" : Function
}

但这也没有解决我的问题。

也许使用var someFunc = new Function(arg, body)会起作用(尚未对其进行测试),但是我无法完全控制传递给vm.runInNewContext的代码,因此我也无法使用该解决方案。

如何让context.someFunc instanceof Function在上下文之外返回true?

2 个答案:

答案 0 :(得分:1)

这是不可能的。使用相同的上下文无法控制第三方模块。当我遇到类似问题时,首先我尝试修复第三方模块并提交拉取请求并解释错误,然后我放弃并切换到new Function()中的eval而不是运行新环境,更符合我的需求。

答案 1 :(得分:1)

确实存在解决方案,但在完整性和性能之间存在权衡。

  1. 只需将返回的函数包装在另一个函数中:

     const context = {}
     vm.runInNewContext("var someFunc = function() {}", context);
     const someFunc = context.someFunc;
     context.someFunc = function(...args) { return someFunc.apply(this, args); }
     console.log(context.someFunc instanceof Function); //true
    

    此解决方案(几乎)没有开销,但它不是一个完整的解决方案。它适用于直接在上下文中公开的已知函数,但它在不太重要的情况下开始崩溃。例如。让它与高阶函数,地图等一起工作需要相当多的工作,我认为甚至不可能涵盖所有奇特的组合。

  2. 使用Proxy按需包装功能

    使用Proxy,不需要提前知道context上公开了哪些值,而是可以根据需要包装函数。这也使得处理更高阶函数变得更容易,因为我们可以递归地代理返回值&参数。然而,正确实施需要付出更多努力,并且会对性能产生重大影响。

  3. 更改新上下文中的Function原型

    const context = { OuterFunction : Function};
    vm.runInNewContext(`
      // setup
      Object.setPrototypeOf(Function.prototype, OuterFunction.prototype);
      //script
      const someFunc = function() {};
    `, context);
    console.log(context.someFunc instanceof Function);
    

    此解决方案使内部Function扩展外部Function,因此任何内部函数都是外部函数的实例。但是,使用setPrototypeOf对性能非常不利,尤其是在更改像Function这样的对象时。所以只要有可能,就应该避免这种情况。