0

私は次のようなことをするスクリプトを持っています:

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 Functioncontext.someFuncは関数ですが、そのコンテキストでは のインスタンスではないためFunction、サードパーティはそれを関数として扱わないため、クラッシュします。次のコンテキストを使用してみました。

var context = {
    "Function" : Function
}

しかし、それでも私の問題は解決しませんでした。

おそらく使用var someFunc = new Function(arg, body)は機能しますが(テストしていません)、渡されたコードを完全に制御vm.runInNewContextできないため、そのソリューションも使用できません。

context.someFunc instanceof Functionコンテキスト外で true を返すにはどうすればよいですか?

4

2 に答える 2

1

不可能です。サードパーティのモジュールを制御できない場合は、同じコンテキストを使用してください。同様の問題が発生した場合、最初にサードパーティモジュールを修正し、何が問題だったのかを説明してプルリクエストを送信しようとしました。次に、新しいコンテキストで実行するのではなく、あきらめてevalに切り替えましたnew Function()。これは私のニーズにより適しています。 。

于 2012-11-07T19:08:46.910 に答える
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. a を使用し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。したがって、可能な限り、これは避ける必要があります。

于 2017-10-27T07:51:24.053 に答える