首先,這些題目不知道在網上有沒有,反正我是被坑過了,欲哭無淚的那種.javascript
題目是這樣的:
使用console.log方法打印變量,若是出現延遲1秒後輸出用=>表示,若是是連續輸出用,表示。java
例如:1=>2,3,4=>5,表示輸出1後,延遲1秒後連續輸出二、三、4,再延遲1秒輸出5es6
for(var i=0;i<5;i++) { setTimeout(function(){ console.log(i) }, 1000) } console.log(i)
怎麼樣,夠簡單吧,可是我特麼居然答錯了,真心想抽本身幾下。
我給出的回答是:5=>4=>4=>4=>4=>4
下面,我說明如下我當時的腦殼裏面是怎麼想的:面試
for(var i=0;i<5;i++) { setTimeout(function(){ console.log(i) // 在這個地方,我認爲在for中限制的條件是i<5,那麼這裏就會是4 }, 1000) // 不知道爲何我當時會認爲這裏延遲的1秒會默認*i,致使=>4=>4=>4=>4=>4 } // 第一個5, 由於var關鍵字能夠提高變量的做用域,出了for循環體做用域外, 其實仍是可以被訪問到的,然而在for循環中最後一次對i的操做是i++,因此這裏會輸出5。 console.log(i)
面試官仍是很不錯的,他反覆提醒我再檢查檢查,有沒有什麼遺漏。因而我盯着for裏面看了大概有30秒,愣是沒發現問題。而後面試官很是和善可親的微笑着跟我對了一遍for,當對到i=5的時候,個人腦殼當時就直冒冷汗,我擦!正確的答案應該是:5=>5,5,5,5,5閉包
再從新分析如下,上面的代碼執行過程至關於:async
// for循環了5次,調用setTimeout方法也是5次,可是setTimeout的延遲都是1秒, // 等setTimeout中的callback函數執行的時候,i的值已是5了, // 因此最終1秒後會連續打印出5個5 setTimeout(function(){ console.log(i) // 第2個5 }, 1000) setTimeout(function(){ console.log(i) // 第3個5 }, 1000) setTimeout(function(){ console.log(i) // 第4個5 }, 1000) setTimeout(function(){ console.log(i) // 第5個5 }, 1000) setTimeout(function(){ console.log(i) // 第6個5 }, 1000) // 這裏沒啥好說的 console.log(i)
這個其實是考察你對閉包的掌握狀況,我給出的回答是:函數
答案1:code
for(var i=0;i<5;i++) { setTimeout(function(j){ console.log(j) }, 1000, i) // 經過setTimeout的第三個參數把i傳入給callback函數的參數j } console.log(i) // 這裏不用動
答案2:ip
for(var i=0;i<5;i++) { (function(j){ // j就是外部傳入的參數i setTimeout(function(){ console.log(j) }, 1000) })(i) // 包一層當即執行函數(IIFE),把i傳入 } console.log(i) // 這裏不用動
作這道題的時候,有一個插曲,我最開始想的是把for中的var換成let就行了,面試官說:一看就知道大家用es6用的太多,我聽了以後,仍是立刻反應過來了,確實不能換成let。作用域
錯誤的答案:
// for中的變量i用let關鍵字聲明以後,只在for循環體內的做用域可以訪問到, // 出了這個循環體做用域,外部就訪問不到了。 for(let i=0;i<5;i++) { setTimeout(function(){ console.log(i) }, 1000) } // 因此,這裏的i會是undefined console.log(i)
看了這個題我想了大概有2分鐘,面試官說,隨便你怎麼改,你只要能輸出這個結果就行,無奈我用了一個最最最最low的辦法。
const count = 5 for(let i=0;i<count;i++) { setTimeout(function(j){ console.log(j) }, 1000 * i, i) } setTimeout(function(){ console.log(i) }, 1000 * i)
面試官看了看說,好吧這個也算你答對了,可是你能夠嘗試如下es六、es7的特性去完成這個(瘋狂暗示),因而我分析了一下:
// 要保證從上往下的執行順序 for(var i=0;i<5;i++) { // 這裏的setTimeout會分別輸出0=>1=>2=>3=>4 setTimeout(function(){ console.log(i) }, 1000) } **// 問題就是在這裏,如何保證for裏面的setTimeout所有執行完成以後,再執行下面的輸出?** // 這裏的i輸出的應該是最後一個=>5 console.log(i)
我想了大概有2分鐘,決定用generator函數,可是還沒寫到一半的時候,面試官叫停了:其實能夠用es7中的async、await配合Promise.all()來完成,不必用generator,你怎麼還退到上一個版本了呢。
好吧,我感受此次面試應該是GG了。
最後我仍是貼出我用generator實現的代碼
function * G() { for(var i=0;i<5;i++){ yield i } return i } var gg = G() do { const {value, done} = gg.next() setTimeout(() => { console.log(value) }, 1000 * value); if (done) { break; } } while(true)
面試官想要的答案:
(async function () { var i = 0 function a() { var array = [] for(;i<5;i++){ array[i] = new Promise((resolve) => { setTimeout((j) => { console.log(j) resolve() }, 1000 * i, i); }) } return array } await Promise.all(a()) console.log(i) })()
最最後,我想說這真的是一次印象很是深入的面試,上面的這些題的知識點平時在開發的過程當中,實際上是比較常見的,只不過比較分散,可是集中到一塊兒可能就會矇蔽你的眼睛,影響你的判斷。 本身繼續加油吧!