[JavaScript] 你應該使用 let 而不是 var 的 3 個重要理由
本篇文將著重於:var的作用域比let還要大,然而「蛋越大跨出步伐越容易扯到蛋」,當你使用var來宣告變數時,會遇到哪些操蛋的事,以及使用let後如何解決。
根據之前所提到的《 JavaScript中 var與let的差別》,我們可以明白var與let關鍵性的區別在於作用域(scope)的不同,而區塊作用域則是比函數作用域較小、較為精確。
在撰寫腳本的日常中,let可以幾乎完美替代var,甚至更適合剛接觸這個語言的人使用。
如果你擔心ES6的語法會讓舊的瀏覽器報錯,這時候你可以透過Babel將腳本轉為ES5的語法。
第一件操蛋的事
for-loop處理回調函數(callback function)時會烙賽,也就是說出現預期外的結果。
如果你是從C-like語言轉過來的人,一定對for loop宣告不陌生,觀看以下程式碼:
setTimeout是一個會去註冊一個callback function,1秒後執行。在作用域沒有管控好的狀況下,loop裡頭的異步事件會去註冊起來,且使用var宣告的變數仍然會直到 i = 3 時才停止(然而這只是幾個瞬間的事)
並在一秒之後,分別被印出這些操蛋的東西。
這不是我要的for迴圈!這不是我要的for迴圈!這不是我要的for迴圈!
讓我們來看看古人怎麼解決這問題吧。
在冷兵器的時代,人類只能透過弓箭飛鏢來做到遠距攻擊,然而槍砲彈藥被發明後,戰爭的方式被改變了!
在ES5之前,我們沒有let這個好用的宣告方式,所以只能透過閉包(closure)來生成一個各自獨立的函數作用域,不囉唆直接看code吧。
運用函數的閉包與立即執行函數(IIFE),你可以建立各自的函數作用域,並把變數i傳進去,用這種方式去解決目前遇到的問題,非常棒。
但放到現在,仍然不夠好,Programmer總希望自己的寫的腳本過一陣子,甚至是不熟悉這個語言的人也能夠看懂。
完美也優美的解決這個問題。
第2件操蛋的事
寫起來很爽,維護起來卻很烙賽的變量提升(hoisting)。
我敢保證變量提升絕對是會讓許多本科生初接觸時說出:「X,這語言是垃圾是不是?」的一大原因。
其實我並不清楚變量提升這個概念是源自於哪個語言,如果有知道的人可以幫我補充,也不太了解其中的哲學。曾有朋友戲稱:變量提升是為了降低Javascript編寫難度,最後在宣告變數作為補充說明,降低門檻。
變量提升是一個值得特別寫一篇來解釋的名詞。
觀察以下代碼,回答執行結果:
答案是(C)。
在scripting language來說,發生這種事的確是滿意外的。
(1) 若是逐行執行,理所當然該印出Reference Error 。
(2) 若是這個區塊在function裡被loop兩次,第二次印出來的結果則是20,因為函數作用域中的變數x已被賦值。
可以把上述代碼,看成這樣:
我認為這是一個JSer必須理解的事,我們了解這些坑後,才能知道ES6/ES7的發展是為了什麼。
回到現代,看看以下代碼:
不過其實這樣子的行為比較合乎直覺。
第3件很操蛋的事
認為hoisting幫助coding速度的人,如果在最後忘記去做var宣告…
若是直接對一沒宣告過的變數做賦值的動作,可能會發生「全域作用域污染」。
這非常嚴重
這個在function內的function內的g變數(有點饒舌),在沒有宣告就賦值,會直接被拉到最外頭的global上(根據宿主環境分別是global & window),如果這是一個寫給他人使用的library,絕對會讓使用者幹到飛天。
本文就到此結束,如果喜歡的話給我一些鼓掌,反之,若覺得有哪裡說的不妥歡迎留言指正及討論。