4

コードを理解しようとしています

for(var i = 0; i < 10; i++) {
    setTimeout((function(e) {
        return function() {
            console.log(e);
        }
    })(i), 1000)
}

ここからhttp://bonsaiden.github.com/JavaScript-Garden/#function.closures

私はこの方法を理解しました:

for(var i = 0; i < 10; i++) {
    (function(e) {
        setTimeout(function() {
            console.log(e);  
        }, 1000);
    })(i);
}

誰かが最初のものを説明することによって私を助けてくれますか?

私が最初のものをどのように理解するかを説明しようと思います、

first i is 0,
setTimeout is called,
self calling function "function(e)" is called with i=0,
Im stuck!! what happens when this function returns a function?
4

3 に答える 3

4

最初に行うのは、タイムアウトが発生した後に呼び出される関数を返すことだけです。

その目的は、forループの反復ごとにサブスコープを作成して、反復ごとに増分iが上書きされないようにすることです。

詳細説明:

これを2つの異なる部分に分解してみましょう。

for(var i = 0; i < 10; i++) {
    setTimeout((function(e) {
        return function() {
            console.log(e);
        }
    })(i), 1000)
}

これは最初の作品です:

for(var i = 0; i < 10; i++) {
    setTimeout(function(){
        console.log(i); //9-9
    },1000);
}

これで、このループを実行すると、常に0から9ではなく9を含むconsole.log()が取得されます。これは、各setTimeoutが。への同じ参照を使用しているためiです。

そのsetTimeout部分を無名関数でラップすると、各反復のスコープが作成され、各setTimeoutが独自のi値を持つことができます。

for(var i = 0; i < 10; i++) {
    setTimeout((function(i) {
        return function() {
            console.log(i); // 0-9
        }
    })(i), 1000)
}

setTimeout内の外部関数は、最初の反復ではiが0、2番目の反復では1などですぐに実行されます。次に、その関数は、setTimeoutが使用する関数である関数を返します。の異なる値を使用して、ループの反復ごとに関数が生成され、返されますi

于 2012-06-26T03:09:07.070 に答える
2

どちらも同じ結果になります。setTimeoutが呼び出されて呼び出され、コンソールに0から9までの数値が書き込まれます。どちらもネストされた関数を使用してiの現在の値をクロージャに入れるため、109をログに記録することはありません。

最初のコードは、setTimeoutが呼び出す関数を返す関数を持つことを選択します。2つ目は、ネストの順序を変更して、クローズドオーバー関数がsetTimeout自体を呼び出すようにします。正味の効果は同じです。

文体的な理由と個人的な選択を除いて、私はどちらかを選択する理由がわかりません。

于 2012-06-26T03:10:12.460 に答える
1

「混乱している場所を指定して、更新された質問を確認してください」

OK、これが長い説明です。の最初のパラメーターはsetTimeout()、指定された遅延後に実行する関数への参照である必要があることに注意してください。最も単純なケースは、他の場所で定義されている関数に名前を付けることです。

function someFunc() {
   console.log("In someFunc");
}

setTimeout(someFunc, 100);

関数自体への参照が必要なため、someFuncパラメーターとして渡すときに括弧がないことに注意してください。setTimeout対比:

setTimeout(someFunc(), 100);   // won't work for someFunc() as defined above

括弧を使用して呼び出し someFunc()戻り値をに渡しますsetTimeout。しかし、上記の私の定義はsomeFunc()明示的に値を返さないので、暗黙的に戻りますundefined-これはと言っているようなものsetTimeout(undefined, 100)です。

ただし、次someFunc()を返す代わりに関数を返すように変更すると機能しundefinedます。

function someFunc() {
   return function() {
      console.log("In the function returned from someFunc");
   };
}

だから今(ついに)あなたの質問からコードに行き着きます:

setTimeout((function(e) {
    return function() {
        console.log(e);
    }
})(i), 1000)

関数を名前で参照して呼び出す代わりにsomeFunc(i)、無名関数を定義し、すぐにとして呼び出します(function(e) {})(i)。その無名関数は別の関数を返し、その返された関数がの実際のパラメーターになりますsetTimeout()。時間切れになると、返された関数が実行されます。返される(内部)関数は(外部)無名関数のスコープで定義されているため、eパラメーターにアクセスできます。

于 2012-06-26T04:19:11.983 に答える