由一道簡單的JS面試題發起的一系列追問,看看你能答對幾個?
不起眼的開始
本文將從一道簡單的Javascript面試題開始,逐漸深入,看看這個過程中你是不是掌握了所有的內容。
我們直接從簡單的代碼開始,看看它的運行結果是什麼?
上面的題目很簡單,只要對作用域,閉包,異步執行等知識有了解,應該會很快說出答案,在本地測試後,輸出的答案如下。
追問1
如果我們需要用箭頭->表示前後輸出有一秒的間隔,那麼最終輸出的答案會是下面的結果1還是結果2呢?
結果1. 5 -> 5 -> 5 -> 5 -> 5 -> 5
結果2. 5 -> 5, 5, 5, 5, 5
如果你對Javascript的定時器有所瞭解的話,會很快知道結果2是正確的。
在循環時設置定時器,幾乎是同時生效的,一般情況下,這5個定時器會在同一秒內執行,結果會立即輸出,因此結果2是正確的。
追問2
如果我期望輸出以下的結果,該怎麼做呢?
5 -> 0, 1, 2, 3, 4
定義輸出函數
有的同學可能會很容易想到通過定義一個專門的輸出函數來執行。
立即執行函數
但是,如果熟悉閉包的同學可能會覺得這種方案比較low,他們會想到利用立即執行函數來解決閉包產生的問題,於是會給出以下答案。
上面的答案利用了立即執行函數來解決閉包造成的問題,是一種比答案1略好的方法。
let
如果熟悉ES6語法的同學又會想到以上兩種方法對於代碼的改動都比較大,如果使用ES6的let命令會可能會更加容易,於是他們有了以下代碼。
首先,我們要確定的是,上述代碼在運行中會報錯,因為let是塊級作用域,i只存在於循環體內部,最後一句i並未定義,在直接輸出時會報錯。
但是既然能夠想到用let命令去做,說明對ES6有一定的瞭解,很不錯。
追問3
如果對於上面的問題,覺得太簡單了,那進行下面一個問題。
需要輸出的形式如下,每隔一秒輸出一個數字,該如何實現?
0 -> 1 -> 2 -> 3 -> 4 -> 5
可能會有很多同學想到使用如下簡單粗暴的方案去做。
對於以上的方案,雖然能實現這個簡單的需求,但是並不能算面試時的一個加分項。
如果考慮到異步執行後的操作,上面的代碼就會顯得很吃力,那該怎麼辦呢?
ES6的Promise
如果你對ES6的Promise有所瞭解,會很容易想到使用Promise去實現。
追問4
既然掌握了ES6的Promise,我們可以更加追求代碼的極致,使用ES7的async和await。
這裡給出使用async和await的解決方案。
總結
本篇文章從一個簡單的Javascript面試題開始,進行了一系列的追問,想一想你能答對幾個追問呢?如果又不會的,記得回去查漏補缺,學習響應的知識。