神奇的函數作用域
今天發現了兩個關於函數作用域的神奇例子,這裡和大家分享分享:
上面這段代碼在運行時會產生什麼結果?
我們來分析一下:
1.創建了全局變數 a,定義其值為 1
2.創建了函數 foo
3.在 foo 的函數體內,if 語句將不會執行,因為 !a 會將變數 a 轉變成布爾的假值,也就是 false
4.跳過條件分支,alert 變數 a,最終的結果應該是輸出 1
看起來無懈可擊的分析,但是實際上,結果錯誤。答案竟然是 2!為什麼?
什麼叫申明?
是指你聲稱某樣東西的存在,比如一個變數或一個函數;但你沒有說明這樣東西到底是什麼,僅僅是告訴解釋器這樣東西存在而已;
什麼叫定義?
是指你指明了某樣東西的具體實現,比如一個變數的值是多少,一個函數的函數體是什麼,確切的表達了這樣東西的意義。
所以上面的代碼實際上可以寫成這樣:
然後又有人會問,不是有個if嗎?if不成立哪就不會為a賦值為2。
因為 JavaScript 沒有塊級作用域(Block Scoping),只有函數作用域(Function Scoping),所以說不是看見一對花括弧 {} 就代表產生了新的作用域,和 C 不一樣!
當解析器讀到 if 語句的時候,它發現此處有一個變數聲明和賦值,於是解析器會將其聲明提升至當前作用域的頂部(這是默認行為,並且無法更改),這個行為就叫做 Hoisting。
怎樣能夠alert出那個a=1?
es6的語法,javascript是有塊級作用域的。
還可以通過閉包的方式實現:
第二個例子:
這個運行的結果是什麼?初略一看,alert(1),但是實際上報錯。
Uncaught TypeError: foo is not a function。
為什麼會這樣?
提升的僅僅是變數名 foo,至於它的定義依然停留在原處。因此在執行 foo() 之前,作用域只知道 foo 的命名,不知道它到底是什麼,所以執行會報錯(通常會是:undefined is not a function)。這叫做函數表達式(Function Expression),函數表達式只有命名會被提升,定義的函數體則不會。
怎麼改?
這個例子也展示了函數聲明與函數表達式的差別,函數申明會放到作用域的頂部,函數表達式則不會。
最後引用很多書中的一句話:「請始終保持作用域內所有變數的聲明放置在作用域的頂部」,相信現在的你對這句話應該有一個認識了。
文章摘自博客園
更多精彩推薦:
IT職業教育:http://www.ujiuye.com/
更多前端知識學習:http://www.ujiuye.com/zt/webqianduan/?wt.db=lsh11tt
※CSS:transition過渡放在偽類中與應用的區別
※自製刻度尺-前端簡易實現「信用」界面
※Python垃圾回收機制 總結
※js數組遍歷和對象遍歷
TAG:IT優就業 |
※《函數項級數的基本概念、收斂域與解析性質》內容小結、題型與典型題
※巧用WEB函數 輕鬆製作單詞表
※函數奇偶性題型總結!
※神經網路中常用的激活函數的說明
※調用無參數的函數
※利用導數研究含參函數的性質
※向右操作符及其相關函數的基本用法
※正弦函數究竟有多神奇?
※在函數中調用函數
※格林函數如何在凝聚態物理的量子場論中起作用?
※遞歸函數及匿名函數配合內置函數的使用
※5個適用於初學者的有用數據分析表達式函數
※關於c語言中函數的調用的兩種方法
※機器學習中常用的損失函數你知多少?
※JS中把函數作為另一函數的參數傳遞方法(總結)
※復用=高階函數和多態
※工作中常用的十個函數公式,必須掌握
※優化函數耗時的問題
※如果一個函數作為另一個函數參數使用,那麼這函數叫做回調函數
※密碼技術之單向散列函數