-1

クロージャーの使用方法を学ぶことで、JavaScript のスキルを適度に拡張しようとしています。以下のコードでは、console.log の出力が 3 から 0 までカウントダウンされると思っていましたが、代わりに -1、-1、-1、-1 になっています。

スコーピングの問題を扱っていることは知っていますが、それだけです。何が欠けていますか?これはどのように適切に記述する必要がありますか、またその理由は何ですか?

function closure_count_test (number)   
{    
    for (var x = 0; x <= number; x += 1)   
    {  
        setTimeout(function() {console.log(number - x);}, x * 1000);  
    }  
}  

closure_count_test(3); 
4

4 に答える 4

0

基本的な言葉で言えば、スコープがどのように機能するかというと、ネストされた関数で参照されるメイン関数の変数が関数の終了後も残り、これらすべての関数が後でそれらにアクセスできるようになります。提供された例では、 x はメイン関数で定義された変数であり、ネストされたすべての関数が後でそれを参照できるようになります。その時までに x の値は number+1 になるため、結果は完全に理にかなっています。これを回避するには、メイン関数の変数を参照しないようにする必要があります。通常のテクニックは次のとおりです。

function closure_count_test (number)   
{    
   for (var x = 0; x <= number; x += 1)   
   {  
       setTimeout(function(x) {
          return function() {console.log(number - x);}
       } (x), x * 1000);
   }  
}

ここで行うことは、引数としてコピーされた独自の x を持ついくつかのネストされた関数を呼び出すことです。これらのそれぞれには、スコープを介してその引数を参照するネストされた関数が 1 つあります。

于 2013-01-31T07:12:28.590 に答える
0

あなたの論理は正しいです。問題は、setTimout が変数の最新の値のみを考慮することです。したがって、setTimout はループの最後であるため、常に x = 0 になります。

setTimout 関数を削除すると、目的の出力が表示されます。

于 2013-01-31T07:06:39.920 に答える
0

xforループによって反復されますが、 の関数setTimeoutは変数 を使用します。この変数xは、関数の作成時に補間されません。これにより、 の最終値が何であれ使用されますx(setTimeoutループの完了後に s が実行されるため)。

これを回避するには、 x の値をそのまま のコールバックに渡す必要がありますsetTimeout。別の関数 (新しいコールバック) を返す関数を呼び出すことができます。

for (var x = 0; x <= number; x += 1) {
    setTimeout(
        (function (x) {
            return function () { console.log(number - x) };
        })(x)
    , x * 1000);  
}

これはx、現在の値を持つ外側のスコープから内側のスコープに渡されます。内部関数はx、関数が作成されたときの値を使用します。

で適切に動作する関数が返されますsetTimeout

http://jsfiddle.net/ExplosionPIlls/QhA3a/

于 2013-01-31T07:13:14.270 に答える
0

これは、x がもう 1 つのクロージャ内でローカライズされるため、機能します。

function closure_count_test(number) {
    for (var x = 0; x <= number; x++)  ( // not need {} as here is only one operator
      function (x) { //Now x - local variable in anonymous function
        return setTimeout(function () {
            console.log(number - x);
        }, x * 1000);
      }(x) // pass x to anonymous function as argument
    ); 
}

closure_count_test(3);
于 2013-01-31T07:07:59.827 に答える