95
function foo(a) {
    if (/* Some condition */) {
        // perform task 1
        // perform task 3
    }
    else {
        // perform task 2
        // perform task 3
    }
}

上記に似た構造の関数があります。タスク 3を関数に抽象化したいのですbar()が、この関数のアクセスを のスコープ内のみに制限したいと考えていますfoo(a)

私が望むものを達成するために、次のように変更するのは正しいですか?

function foo(a) {
    function bar() {
        // Perform task 3
    }

    if (/* Some condition */) {
        // Perform task 1
        bar();
    }
    else {
        // Perform task 2
        bar();
    }
}

上記が正しい場合、呼び出されるbar()たびに get が再定義されますか? foo(a)(ここでCPUリソースの浪費が心配です。)

4

5 に答える 5

136

はい、あなたが持っているものは正しいです。いくつかのメモ:

  • barfunction を呼び出すたびに作成されますが、次のようになりますfoo
    • 最新のブラウザでは、これは非常に高速なプロセスです。(一部のエンジンは、コードを 1 回だけコンパイルし、そのコードを毎回異なるコンテキストで再利用する場合があります。Google の V8 エンジン [Chrome やその他の場所で] は、ほとんどの場合これを行います。)
    • また、何をbar行うかによって、一部のエンジンは、関数呼び出しを完全に排除して、それを「インライン化」できると判断する場合があります。V8 はこれを行います。V8 だけがそうするエンジンではないと確信しています。当然、コードの動作が変わらない場合にのみ、これを行うことができます。
  • bar毎回作成した場合のパフォーマンスへの影響は、 JavaScript エンジンによって大きく異なります。些細な場合bar、検出できないものからかなり小さいものまでさまざまです。何千回も続けて呼び出していない場合foo(たとえば、mousemoveハンドラーから)、私はそれについて心配しません。あなたがそうであったとしても、遅いエンジンで問題が発生した場合にのみ心配します. これはDOM 操作を含むテスト ケースです。これは、影響があることを示唆していますが、取るに足らないものです (おそらく DOM によって洗い流されます)。これは、はるかに高い影響を示す純粋な計算を行うテストケースですが、率直に言って、マイクロ秒かかるもので92%の増加であっても、マイクロ秒の違いについて話している.発生するまでの数秒は、まだ非常に高速です。実際の影響が見られるまで/見ない限り、心配する必要はありません。
  • bar関数内からのみアクセスでき、その関数呼び出しのすべての変数と引数にアクセスできます。これにより、これは非常に便利なパターンになります。
  • 関数宣言を使用したため、宣言を配置する場所 (上、下、または中間 — フロー制御ステートメント内ではなく、関数の最上位レベルにある限り) は問題ではないことに注意してください。構文エラー)、段階的なコードの最初の行が実行される前に定義されます。
于 2012-04-18T07:00:11.080 に答える
15

これがクロージャーの目的です。

var foo = (function () {
  function bar() {
    // perform task 3
  };

  function innerfoo (a) { 
    if (/* some cond */ ) {
      // perform task 1
      bar();
    }
    else {
      // perform task 2
      bar();
    }
  }
  return innerfoo;
})();

Innerfoo (クロージャー) は bar への参照を保持し、innerfoo への参照のみが、クロージャーを作成するために一度だけ呼び出される無名関数から返されます。

このように外からバーにアクセスすることはできません。

于 2012-04-18T07:30:57.780 に答える
9
var foo = (function () {
    var bar = function () {
        // perform task 3
    }
    return function (a) {

        if (/*some condition*/) {
            // perform task 1
            bar();
        }
        else {
            // perform task 2
            bar();
        }
    };
}());

クロージャーは、bar()contained のスコープを保持し、自己実行型の無名関数から新しい関数を返すことで、より可視的なスコープを に設定しますfoo()。匿名の自己実行関数は 1 回だけ実行されるためbar()、インスタンスは 1 つしかなく、 の実行ごとにfoo()それが使用されます。

于 2012-04-18T07:13:21.673 に答える
5

はい、うまくいきます。

外側の関数を入力するたびに内側の関数が再作成されるのではなく、再割り当てされます。

このコードをテストする場合:

function test() {

    function demo() { alert('1'); }

    demo();
    demo = function() { alert('2'); };
    demo();

}

test();
test();

、、、、1ではなく、、、と表示されます。2121222

于 2012-04-18T07:06:17.340 に答える