41

繰り返し述べたように、Function コンストラクターを使用することは悪い習慣と見なされます ( ECMAScript 言語仕様、5版、§ 15.3.2.1も参照してください)。

new Function ([arg1[, arg2[, … argN]],] functionBody)

(すべての引数は引数名を含む文字列であり、最後の (または唯一の) 文字列には関数本体が含まれます)。

要約すると、Opera チームによって説明されているように、遅いと言われています。

[…] コンストラクターがソース コードを表す文字列に対して呼び出されるたびFunction に、スクリプト エンジンは、ソース コードを実行可能コードに変換する機構を開始する必要があります。これは通常、パフォーマンスの面でコストがかかります。たとえば、単純な関数呼び出しよりも簡単に 100 倍のコストがかかります。(マーク 'ターキン' ウィルトン ジョーンズ)

MDC のこの投稿によると、それほど悪くはありません(ただし、現在のバージョンの Firefox を使用して自分でテストしたわけではありません)。

クロックフォードは、次のように付け加えています。

[t]言語の引用規則により、関数本体を文字列として正しく表現することが非常に困難になります。文字列形式では、初期エラー チェックを実行できません。[…] そして、各関数は独自の独立した実装を必要とするため、メモリの無駄です。

もう一つの違いは、

Function コンストラクターによって定義された関数は、(すべての関数が継承する) グローバル スコープ以外のスコープを継承しません。( MDC )

new Functionこれとは別に、動的コンテンツを使用して作成する場合は、悪意のあるコードが挿入されないように注意する必要があります。

そうは言っても、TJ Crowder は答えで次のように述べています。

[t]同様の […] new Function(...) が必要になることはほとんどありません。これも高度なエッジ ケースを除きます。

それで、今、私は疑問に思っています: これらの「高度なエッジケース」とは何ですか? Function コンストラクターの正当な使用法はありますか?

4

7 に答える 7

19

NWMatcher — Diego Perini による Javascript CSS セレクターおよびマッチャー —Functionコンストラクター ( 1234など) を使用して、セレクター マッチャーの非常に効率的なバージョンを作成 (「コンパイル」) します。

ベンチマーク(Chrome 5 で実行したばかり) がそれを物語っています。

代替テキスト

NWMatcher と Sizzle の違いに注意してください。これは非常によく似たセレクター エンジンですが、関数のコンパイルがないだけです:)

余談ですが、ECMAScript 5はの呼び出しでエラーをスローしませんFunction。厳密モードでも「標準」モードでも。ただし、厳密モードでは、「eval」や「arguments」などの識別子の存在にいくつかの制限が導入されます。

  • そのような名前で変数/関数/引数を宣言することはできません:

    function eval() { }
    var eval = { };
    function f(eval) { } 
    var o = { set f(eval){ } };
    
  • そのような識別子に割り当てることはできません:

    eval = { };
    

evalまた、strict モードでは、セマンティクスが ES3 のセマンティクスとわずかに異なることに注意してください。Strict モードのコードは、呼び出し元の環境で変数や関数をインスタンス化できません。

 eval(' "use strict"; var x = 1; ');
 typeof x; // "undefined"
于 2010-06-11T22:00:15.570 に答える
9

jQuery はこれを使用して、JSON パーサー オブジェクトが利用できない場合に JSON 文字列を解析します。私には合法のようです:)

        // Try to use the native JSON parser first
        return window.JSON && window.JSON.parse ?
            window.JSON.parse( data ) :
            (new Function("return " + data))();
于 2010-06-11T20:44:06.610 に答える
8

new Function()私が開発している Web アプリの 1 つで、コンストラクターをインライン JS インタープリターとして使用します。

function interpret(s) {
  //eval(s); <-- even worse practice
  try {
      var f = new Function(s);
      f();
    }
  catch (err) {
      //graceful error handling in the case of malformed code
  }
}

AJAX ( iframe ではないinterpret()) を介してストリーミングするものを取得すると、継続的にオンになりreadyStateChange == 3ます。これは驚くほどうまく機能します。

編集new Function(): これは、が より断然速いことを示す明確なケーススタディですeval()。つまり、 の代わりに eval を (めったに?) 使用しないでくださいnew Function()

http://polyfx.com/stuff/bsort.html <- 1000 反復バージョンでは、ブラウザがクラッシュする可能性があります

http://polyfx.com/stuff/bsort10.html <- 短いバージョン

Eval は平均して より約8 倍遅くなりnew Function()ます。

于 2010-06-11T20:49:03.650 に答える
7

John Resig は、Function コンストラクターを使用して、asp 構文で記述されたクライアント側テンプレートの「コンパイル済み」バージョンを作成しました。 http://ejohn.org/blog/javascript-micro-templating/

于 2010-06-11T21:29:18.547 に答える
4

これは私の他の答えとは別のケースです。

しばらく前に Function コンストラクターを使用して、繰り返し呼び出されるカスタム文字列フォーマッターを作成しました。関数を作成するオーバーヘッド (これは、あなたが話しているパフォーマンスの問題だと私は考えています) は、実行時に特定のフォーマット文字列を処理するために特別に作成されたカスタムビルド関数のパフォーマンスの向上によってはるかに上回っていたため、大量の無関係なケースを評価する必要はありませんでした — さらに言えば、フォーマット文字列を解析する必要もありませんでした。正規表現のコンパイルに少し似ていると思います。

于 2010-06-11T20:51:59.620 に答える
3

私がそれのために来た唯一の合法的な使用は、私がこれを書いたときです:

Function.prototype.New = (function () {
  var fs = [];
  return function () {
    var f = fs [arguments.length];
    if (f) {
      return f.apply (this, arguments);
    }
    var argStrs = [];
    for (var i = 0; i < arguments.length; ++i) {
      argStrs.push ("a[" + i + "]");
    }
    f = new Function ("var a=arguments;return new this(" + argStrs.join () + ");");
    if (arguments.length < 100) {
      fs [arguments.length] = f;
    }
    return f.apply (this, arguments);
  };
}) ();

このコードを使用すると、キーワードFunction.prototype.applyを「使用」しながら使用できます。new

例:

function Foo (x, y, z) {
  this.x = x;
  this.y = y;
  this.z = z;
  this.otherArgs = Array.prototype.slice.call (arguments, 3);
}

var foo = Function.prototype.New.apply (Foo, [1, 2, 3, 4, 5, 6, 7]);
// /*equiv*/ var foo = Foo.New.apply (Foo, [1, 2, 3, 4, 5, 6, 7]);
// /*equiv*/ var foo = Foo.New (1, 2, 3, 4, 5, 6, 7);
var bool = true
  && foo.x == 1
  && foo.y == 2
  && foo.z == 3
  && foo.otherArgs.length == 4
  && foo.otherArgs [0] == 4
  && foo.otherArgs [1] == 5
  && foo.otherArgs [2] == 6
  && foo.otherArgs [3] == 7
  ;

alert (bool);
于 2010-06-11T22:18:35.037 に答える
2

コードの文字列を複数回実行したい場合があります。Function コンストラクターを使用すると、一度コンパイルするだけで済みます。

たとえば、イベントをポリフィルしている場合は、イベント属性を取得して、イベント引数を期待する関数を構築できます。

2 つを組み合わせて、ある場所でコンパイルし、別の場所で実行しても、コードの文字列が期待する変数に引数を渡すことができます。

于 2011-12-10T00:11:59.507 に答える