1

こんにちは、私は JavaScript が初めてで、次のコードを理解できません。

var createAdders = function () {

    var fns = [];

    for (var i = 1; i < 4; i++) {

        fns[i] = (function (n) {
            return i + n;
        });
    }
    return fns;
}
var adders = createAdders();
adders[1](7); //11 ??
adders[2](7); //11 ??
adders[3](7); //11 ??

私が理解していることから、7は引数として渡されますがcreateAdders()、変数に7を割り当てないためcreateAdders()、匿名関数内の次の関数に7が渡され、変数に割り当てられますn

私の論理は正しいですか?

上記のコードは機能しているように見えますが、すべての呼び出しの結果は 11 です。クロージャーが役立つ状況の例として、非常に信頼できるブログでこのコードを見つけました。閉鎖の利点。

var createAdders = function () {
    var fns = [];
    for (var i = 1; i < 4; i++) {
        (function (i) {
            fns[i] = (function (n) {
                return i + n;
            });
        })(i)     //// why is (i) used here? what purpose does it serve??////
    }
    return fns;
}

var adders = createAdders();
adders[1](7); //8 
adders[2](7); //9 
adders[3](7); //10

ここにも同じロジックが適用されますか?

n に値 7 がどのように割り当てられているかを理解する必要があります

新しいコードで (i) が関数の最後に使用されているのはなぜですか?

4

3 に答える 3

2

JavaScript では、ブロック スコープはなく、関数スコープしかありません。

最初の例では、i宣言された のみがスコープに属しています。つまり、ループ内createAddersで作成されたすべての関数は、スコープ チェーン内で同じようにシークし、同じ値を返します。コードで説明:fori

//   here's the only `i` declaration
for (var i = 1; i < 4; i++) {

    fns[i] = (function (n) {
        return i + n; //this line will retrieve the `i` variable declared above,
                      //that being always 4 after the loop ends
    });
}

2 番目の例では、ループ内にIIFEを含む新しいスコープを作成しています。これにより、反復ごとに新しい実行コンテキストが作成されます。

IIFE 内で作成された関数は、IIFE の実行コンテキストにアクセスしますi。これiは、アウターを IIFE に渡しているため、反復ごとに一意でiあり、IIFE の正式なパラメーターになりますi

iつまり、反復ごとに、IIFE ラッパーを介して独自の新しい実行コンテキストが作成されます。

コメントを順番に読んでください。

//  1. Outer `i` declared here
for (var i = 1; i < 4; i++) {
    (function (i) {// 3. Outer `i` becomes the formal parameter `i` of the IIFE, 
                   // it is a "different" `i` in a new execution context (scope)
        fns[i] = (function (n) {
            return i + n; // 4. seeks the `i` value of the IIFE
        });
    })(i) // 2. Outer `i` passed to IIFE
}

IIFE 内で作成された関数を呼び出すと、スコープ チェーンは、関数が作成された IIFEiの仮パラメータである、スコープ チェーン内の「最も近い」ものを取得します。i

于 2012-11-19T17:34:57.357 に答える
1

最初のブロックでは、createAdders()関数の配列が返され、すべての関数 (関数本体の内側のforループで作成された) は、パラメーター(7 の値) とループで作成された変数を合計します。の値は 4 です (これは 11 を説明します)。createAdders()ni

呼び出しをadders[1](7)行うと、配列fnsの位置 1 に格納された関数が返されますn = 7。次に、パラメーターを使用して関数を呼び出すと、関数はこのパラメーターと関数のi変数を合計します (この時点でのcreateAdders値はinvoke です) 。4adders[1](7)

于 2012-11-19T17:25:53.010 に答える
0

javascript では、外側の関数の実行が終了した後でも、内側の関数は常に外側の関数変数にアクセスできます。この動作は閉鎖と呼ばれます。

最初のスニペットでは、3 回以上反復し、関数を配列内にプッシュしています。ループの実行が終了すると、変数 i は 4 に設定されます。配列内にプッシュした関数は、この変数にアクセスできます。したがって、配列のどのインデックスで関数を実行しても、常に 11 (4 + 7) になります。

2 番目のスニペットでは、自己実行匿名関数を使用して i の値を保持しています。この無名関数は、すべての対話ですぐに実行されます。この匿名関数内で定義されたクロージャー関数のため、毎回 i の新しい値への参照があります。

したがって、配列内にそれぞれ個別の値 i (1,2,3) を持つ 3 つの関数があり、次のように 2 番目のスニペットを記述すると、より明確になります。

var createAdders = function(){
var fns = [ ];
for (var i=1; i<4; i++) { 
    (function(a) {
        fns[a] = (function(n) {
            return a+n;
        });
    })(i)    
}
return fns;}

JavaScript では、関数を戻り値として持つことができます。次に、配列はそれ自体に関数を格納できます。

コードで行っていることは、単一の引数を受け入れる配列内に関数をプッシュし、後でそれを呼び出すことです。

adders[1](7);

次のように分解できます

var fn = adders[1];
fn(7); //thats how n is set to 7
于 2012-11-19T18:26:03.840 に答える