2

次の JavaScript について考えてみましょう。

<script>
function Ninja() {
   var feints = 0;
    this.getFeints = function() {
        return feints;
    }

    this.feint = function() {
        feints++;
    }

    this.increaseByTwo = function() {
        feints = feints + 2;
    } 
}

var ninja = new Ninja();
ninja.feint();

console.log(ninja.getFeints());  //outputs one
ninja.increaseByTwo();
console.log(ninja.getFeints());  // outputs three
</script>

上記のコードで 4 つのクロージャーが作成されると言うのは正しいですか

  • 忍者用の 1 つ - これはちょっと無関係です。
  • Ninja 内の内部関数ごとに 1 つ。これら 3 つのクロージャはそれぞれ同じものを指しています。

それとも、JavaScript は 2 つのクロージャーを作成しますか?

  • 忍者用の 1 つ - これはちょっと無関係です
  • 3 つの内部関数の 1 つ。3 つの内部関数は同じクロージャーを共有します。
4

3 に答える 3

2

3 つの内部関数はすべて、同じ環境を指すクロージャーを持っているため、内部の変数があります。これは通常、クロージャを持つことの要点です:

コンピューター サイエンスでは、クロージャー (レキシカル クロージャーまたは関数クロージャーとも呼ばれます) は、参照環境 (その関数の非ローカル変数 (自由変数とも呼ばれます) への参照を格納するテーブル) を伴う関数または関数への参照です。 . 1 単純な関数ポインターとは異なり、クロージャーは、直接のレキシカル スコープの外で呼び出された場合でも、関数が非ローカル変数にアクセスできるようにします。

これらの参照を保持していることを常に認識しているとは限らないため、これはメモリリークの頻繁な原因であることに注意してください。

Google の Javascript スタイル ガイドでクロージャについて説明されている内容を参照してください。

ただし、覚えておくべきことの 1 つは、クロージャーはそれを囲むスコープへのポインターを保持するということです。その結果、クロージャを DOM 要素にアタッチすると、循環参照が作成され、メモリ リークが発生する可能性があります。

于 2012-10-15T16:16:13.670 に答える
1

ただ、

Ninja 内の内部関数ごとに 1 つ

大量の を作成する場合は、を使用して拡張するのNinjaが賢明です。Ninjaprototype

したがって、次のようにします。

var Ninja = (function () {
    function Ninja(){
        this.feints = 0;
    };

    Ninja.prototype.getFeints = function() {
        return this.feints;
    }

    Ninja.prototype.feint = function() {
        this.feints++;
    }

    Ninja.prototype.increaseByTwo = function() {
        this.feints = this.feints + 2;
    }

    return Ninja;
})();

http://jsfiddle.net/ZM3tH/

于 2012-10-15T16:15:53.333 に答える
0

そのコードを実行するとどうなりますか? 段階的に見てみましょう:

  1. Ninjaコンストラクター関数を宣言します。グローバル変数スコープ内。
  2. Ninjaコンストラクター を呼び出します
    1. これにより、宣言さfeintsれたグローバル スコープ内に存在する新しい変数環境 ( を含む) が作成されます。Ninja
    2. その変数環境を指す 3 つの無名関数が作成されます。
    3. いくつかの割り当てが行われ、オブジェクトが返されます。
  3. ガベージ コレクターは Ninja の変数環境を収集できるかどうかをチェックします。
  4. でメソッドを実行しますninja。それぞれについて、
    1. 関数が宣言されたスコープ内に存在する新しい空の変数環境が作成されます
    2. 関数が何かを実行した後、ローカル環境はガベージ コレクションされます。

では、クロージャーとは何ですか?私の理解では、プライベート変数環境がNinja()関数呼び出しよりも長生きするという事実です。したがって、コードは1 つのクロージャーのみを作成します。

有用な情報を提供する @dystroy の回答も参照してください。また、どこかで技術的に間違った用語を使用していたら申し訳ありません。ご存知のように、EcmaScript 仕様では、実行コンテキストとスコープについて説明した「変数環境」を呼び出します。セクション 10を参照してください。

于 2012-10-15T16:44:19.547 に答える