JS: 一個小例子引發的思考

一個小例子引發的思考

emmmm……

最近在看一個開源庫,看其中的栗子中發現了一段很有意思的代碼。栗子簡化一下是下面的這個樣子的:

function a() { console.log('a'); setTimeout(b); }
function b() { console.log('b') }
function c() { console.log('c') };

a(c());

可能你覺得這沒什麼,不就幾個簡單的方法調用麼,有什麼複雜的?那麼我們先來看一下在Chrome的控制檯裏面會輸出什麼?

可能的確如你所料,控制檯依次輸出了c、a、b(雖然有個不知道什麼鬼的undefined,這個等下再說),那說明你對JS中函數的執行順序有一定的瞭解。的確,前面聲明瞭三個方法,a,b,c,然後加上括號使a成爲語句執行。但是a(c())這種寫法怪怪的,內部怎麼執行的?還有這個輸出怎麼會有一個undefined(面試題埋坑啊)?

我同樣也有這樣的疑問,那麼深究之前,先整理一下我們的疑問。

這段代碼的輸出是什麼?a(c())這種寫法是什麼鬼?undefined是什麼鬼?setTimeout不寫時間參數會咋樣?會有瀏覽器差異麼?

那麼我們一個個的來爲我們疑問來尋找答案……

這段代碼的輸出是什麼?爲什麼會有這樣子的輸出?

其實答案已經看到了,就是c、a、b。因爲JS是單線程執行的,所以在執行a方法的過程中,先執行了()中的語句,也就是c()方法,所以順序執行也就是c、a、b。

emmm……說了和沒說一樣,沒關係往下看。

a(c())這種寫法是什麼鬼?

接着上個答案的來說。要明白a(c())這種寫法是什麼鬼?我們得先了解在JS中()是個什麼作用?對於普通的語句,()直接執行。對於函數來說,JavaScript解釋器會在默認的情況下把遇到的function關鍵字當作是函數聲明語句(statement)來進行解釋的。先來看下面的這幾個栗子:

(111)   // 常量,當做語句處理。打印 111

(var a)  // 變量聲明。 報錯

(a = 1)  // 賦值語句,不要寫';'。打印 1

function(){console.log('aa')}()  // 匿名函數,不是標準的函數聲明語句。報錯

(function(){console.log('aa')}())  // 立即執行函數。打印 aa

(function(){console.log('aa')})()  // 立即執行函數。打印 aa

所以其實大致的意思已經很明瞭。 通俗的來講就是 因爲c首先是一個很標準的函數語句,然後()又可以執行語句,所以a(c())的執行順序就是先執行了c方法,然後繼續執行a方法。如果換成下面的這種方式c就不會執行了:

a(c());   // c、a、b

a(c);   // a、b

a(function(){console.log('nini')}); // a、b

好像也沒有那麼繞……

undefined是什麼鬼?

基本路子搞明白了,那麼這個undefined是什麼鬼?其實很簡單,這是Chrome控制檯的一種默認機制,對於執行語句來說,控制檯會默認去拿上一行語句的輸出。

a = 1;  // 打印 1

var a = 1; // 打印 undefined, 因爲這是兩行語句

(function(){return 1;})() // 打印 1

function a() {} a(); // 打印 undefined

function a() { return 11; } a(); // 打印 1

所以打印undefined的問題找到了,那麼問題來了,node中會不會打印呢?嘗試了一波兒發現,node中並不會打印,所以同樣是V8引擎,但是控制檯這一塊兒還是有差距的。

setTimeout不寫時間參數會咋樣?

終於碰到了最喜歡的setTimeout方法。查閱一堆亂七八糟資料後,setTimeout不寫時間參數的話,會由瀏覽器默認給加上延遲參數,具體多少各家瀏覽器都不一樣。

emmm……無所謂了,那麼 setTimeout(func,0) 和 setTimeout(func) 有什麼區別麼?

下面兩張圖是在控制檯進行了4次的對比試驗。

沒有時間參數

時間參數爲0

好像加上0的確會快一些。不過我們也知道,即使是0,setTimeout 的作用也只是加到當前執行的事件隊列當中,而且在瀏覽器端每次執行也會有4ms的延遲。具體的可以看一看我的另一篇: 看了這麼久JS,事件隊列你真的懂嗎?

關於瀏覽器的4ms的差異延遲,我們暫時不用在意。當我們需要遇到性能瓶頸時可以去研究一下,具體的方案的實現還都挺有意思的。

會有瀏覽器差異麼?

有,不過控制檯的輸出影響不大。不必在意。

結尾

以上,基本上該思考的都思考了,不知道你看到這裏,還有什麼在思考的,倘若有的話,不妨說來聽聽。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章