2017-06-17 11 views
8

私はletとvarの違いを知っています。 letはブロックスコープで、varは機能スコープです。setTimeoutの中のletとvarの違いは?

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

output : 3 
     3 
     3 

Iは、(console.log(i)私の範囲がグローバルであるため、iの値が3になる時点で実行される)動作している方法コードスニペット上知っています。

しかし

for(let i=0; i< 3; i++){ 
    setTimeout(function(){ 
     console.log(i); 
    }, 10); 
} 

output : 1 
     2 
     3 

私を混乱させ、上記のコードスニペット。私によれば、参照エラーが発生するはずです(console.log(i)が実行され、ローカルスコープではグローバルスコープではiの値が見え、グローバルでは宣言/定義されていないので参照エラーとなるはずです)

実行時に2nd forループがどのように機能するのか説明できる人はいますか?

+2

letは、letを使用すると、各繰り返しに対してiの新しいインスタンスをクローズします。 – Blindman67

+0

「参照エラー」がスローされる場合、クロージャの種類は機能しません。関数のスコープは 'var'でも、' let'のスコープでもありません。 –

+0

あなたは時間があるときこの[記事](http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html)に行ってください。それは、スコープ、ホイストなどを本当にうまく説明します。 – Fahmi

答えて

2

このコンテキストでletを使用すると、各繰り返しで新しいバインディング/スコープが作成されます。あなたはvarとES5で同様の動作を実現したい場合は、生命維持を使用する必要があります。

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

3

機能はすべての変数は、その超える閉じますので(letを使用して)第二の例は動作しますそれが宣言されたときに範囲内にある。 forループの各反復で新しい変数がletで作成され、タイムアウトの関数が変数をクローズし、参照を保持します。関数がタイムアウト後に参照解除されると、クロージャ変数も同様に参照されます。

関数クロージャの詳細については、How do JavaScript closures workを参照してください。

3

これは閉鎖の魔法です。側では、あなたのループ

for(let i=0; i< 3; i++){ 
    setTimeout(function(){ 
     console.log(i); 
    }, 10); 
} 

あなたは関数に

function(){ 
    console.log(i); 
} 

を宣言しているまた、ループ自体はletで定義されたblock

for(let i=0; i< 3; i++){ 
    // this is a block scope because it is contained in 
    // braces 
} 

変数を宣言ブロックがスコープされています。そのためclosure

は、あなたがループ内で宣言する機能は、それがガベージコレクトされるまでをスコープその範囲とその親で宣言されたすべての変数にアクセスすることができます。

クロージャは、関数とその関数が宣言されている語彙環境 の組み合わせです。この環境は、閉鎖 が作成された時点でスコープ内にあったローカル変数 で構成されます。setTimeoutによって使用される関数が作成されるとき

変数iは、有効範囲内あります。参照されるiは、ループの反復ごとに異なるiのインスタンスです。

関数は、宣言した間隔が経過するまで存在します。そのため、ループ内で宣言された3つの関数のそれぞれがiという値を出力するのはこのためです。 これは包含スコープ内で宣言され、関数で利用可能なままです。

関連する問題