一道經典面試題-----setTimeout(function(){},0)
轉載: http://www.w3cfuns.com/notes/17398/e8a1ce8f863e8b5abb530069b388a158/page/3.html#tagsbar
先看題:
1 for (var i = 0; i < 3; i++) { 2 setTimeout(function() { 3 console.log(i); 4 }, 0); 5 console.log(i); 6 }
1 setTimeout(function() { 2 console.log(1); 3 }, 0); 4 console.log(2); //先打印2,再打印1
因為是setTimeout是異步的。
正確的理解setTimeout的方式(注冊事件): 有兩個參數,第一個參數是函數,第二參數是時間值。 調用setTimeout時,把函數參數,放到事件隊列中。等主程序運行完,再調用。
就像我們給按鈕綁定事件一樣:
1 btn.onclick = function() { 2 alert(1); 3 };
這么寫完,會彈出1嗎。不會!!只是綁定事件而已! 必須等我們去觸發事件,比如去點擊這個按鈕,才會彈出1。
setTimeout也是這樣的!只是綁定事件,等主程序運行完畢后,再去調用。
setTimeout的時間值是怎么回事呢?
1 setTimeout(fn, 2000)
程序會不會報錯? 不會!而且還會准確得打印1。為什么? 因為真正去執行console.log(i)這句代碼時,var i = 1已經執行完畢了!
所以我們進行dom操作。可以先綁定事件,然后再去寫其他邏輯。
1 window.onload = function() { 2 fn(); 3 } 4 var fn = function() { 5 alert('hello') 6 };
這么寫,完全是可以的。因為異步!
es5中是沒有塊級作用域的。
1 for (var i = 0; i < 3; i++) {} 2 console.log(i); //3,也就說i可以在for循環體外訪問到。所以是沒有塊級作用域。
原題等價於:
1 var i = 0; 2 setTimeout(function() { 3 console.log(i); 4 }, 0); 5 console.log(i); 6 i++; 7 setTimeout(function() { 8 console.log(i); 9 }, 0); 10 console.log(i); 11 i++; 12 setTimeout(function() { 13 console.log(i); 14 }, 0); 15 console.log(i); 16 i++;
因為setTimeout是注冊事件。根據前面的討論,可以都放在后面。
原題又等價於如下的寫法:
1 var i = 0; 2 console.log(i); 3 i++; 4 console.log(i); 5 i++; 6 console.log(i); 7 i++; 8 setTimeout(function() { 9 console.log(i); 10 }, 0); 11 setTimeout(function() { 12 console.log(i); 13 }, 0); 14 setTimeout(function() { 15 console.log(i); 16 }, 0); //彈出 0 1 2 3 3 3
怎么保證能彈出0,1, 2呢?
1 for (var i = 0; i < 3; i++) { 2 setTimeout((function(i) { 3 return function() { 4 console.log(i); 5 }; 6 })(i), 0); //改為立即執行的函數 7 console.log(i); 8 }