動態語言的一點小小小小小小小小小特性 - hoist篇
今天我要來講動態語言的故事了,因為javascript最多,所以拿javascript來說明感覺好像蠻好講的,加上為了上色好看所以用了不少gist(羞
好,故事是這樣的,想必很多人寫javascript的時候都會遇到有重複命名的情況
為了簡單說明,先來看以下這段code:
從上面的情況正常會認為var foo = 1
被function foo
覆蓋了,所以var foo = 1
應該會是無效的行為,但是實際上執行這段程式會得到下面的結果:
1
從上面的結果,我們可以知道,最後會被執行的是var foo = 1
而不是function foo
,這是為什麼呢?
參考一下MDN的說明:
Because variable declarations (and declarations in general) are processed before any code is executed, declaring a variable anywhere in the code is equivalent to declaring it at the top.
在interpreter的認知中,會先去掃一次所有的function scope的內容,並且將function都置於程式的最頂端,所以,經過interpreter的洗禮後,剛剛的程式會變成:
function foo
因為interpreter的判定,而被移動到最上方,造成下面只要同名的變數都會被拉到var foo
的數值裡面,程式會因為這樣造成無法預期的結果。
或許這樣沒什麼感覺,那來一段比較有情境的code吧!
在這段程式碼當中,我們做了三個動作
- 宣告我們的分數
score
- 針對我們宣告的分數做加總,那因為也是分數,所以我們這裡也是用
score
- 針對我們加總完分數進行印出
那執行到第三步驟的時候你可能會得到類似的訊息
console.log(score());
^
TypeError: score is not a function
at Object.<anonymous> (/Users/michael/Downloads/test.js:12:13)
at Module._compile (module.js:541:32)
at Object.Module._extensions..js (module.js:550:10)
at Module.load (module.js:458:32)
at tryModuleLoad (module.js:417:12)
at Function.Module._load (module.js:409:3)
at Module.runMain (module.js:575:10)
at run (bootstrap_node.js:352:7)
at startup (bootstrap_node.js:144:9)
at bootstrap_node.js:467:3
好了,到這裡瞭解問題在哪了吧?對於程式語言來說,function的命名一定是優先於variable的命名,這裡我們有一個專有名詞「hoist」,他主要是指說將宣告提升到頂端的行為,所以像是下面這種程式也是有效的:
上述的程式明明就是function在下面,但是由於hoist的特性,導致foo()
也可以正確的被執行,那有人可能就會問啦:「我程式該如何跟我預期的行為一致?」
目前比較好的解法就是將function與variable移到同一層,使得function與variable有同樣的行為模式,例如:
將function宣告成變數後,到指定行程式才會被正確的執行,可以參考以下討論: http://stackoverflow.com/questions/336859/javascript-function-declaration-syntax-var-fn-function-vs-function-fn
以上介紹到這,開發中能儘量避掉這類的雷就努力避免吧~~