function createFunction1(){ for(var i=0;i<5;i++){ function s(){ console.log(i); } s(); } } createFunction1(); //0 1 2 3 4;
以上是一個正常的函數。
function createFunction2(){ for(var i=0;i<5;i++){ setTimeout(function timer(){ console.log(i); },i*1000); } } createFunction2(); //每隔1秒輸出‘4’、共輸出5次
並不會按照我們預想的每隔1秒分別輸出0、1、2、3、4
分析一下原因:
此函數在for循環的第一層是setTimeout函數,他的執行和createFunction1中的s函數一樣,將按分別在1秒后、2秒后、3秒后執行。但這兒需要注意的是,setTimeout的內部函數timer並沒有立即執行,for循環中的i將會把值分別賦給setTimeout外部參數中的i,但其內部函數timer()則只會引用包含函數setTimeout()中的變量的最后一個值。因為閉包所保存的是整個變量對象,而不是某個特殊的變量。當然其中的這些處理變化,都是瞬間完成的,與執行時間並無關系,即使把1000改成0效果還是一樣的。
重寫一下這個函數:
function createFunction3(){ for (var i=0;i<5;i++){ (function(j){ setTimeout(function timer(){ console.log(j); },i*1000); })(i); } } createFunction3(); //每隔1秒分別輸出0 1 2 3 4
再看上面這個例子,給外部包裝了一個立即執行的匿名函數,setTimeout里面的匿名函數不再引用外部函數的參數,而是直接引用外部匿名函數的參數,這時,一切就會按照我們預想的來執行了。