一道經典面試題-----setTimeout(function(){},0)(轉)


一道經典面試題-----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 }
結果是:0 1 2 3 3 3 很多公司 面試都愛出這道題,此題考察的知識點還是蠻多的。 都考察了那些知識點呢? 異步、作用域、閉包。 我們來簡化此題:
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循環體外訪問到。所以是沒有塊級作用域。
這回我們再來看看原題。 原題使用了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 }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM