呃剛剛寫了好多,結果被我誤操作覆蓋掉了,我的心血╥﹏╥…
沒關係重新寫一遍,也提醒同樣在這個平台寫博客並且像我一樣喜歡用markdown語言碼字的同學
「把線上到草稿都儲存」是個好習慣,嗯嗯
今天雙十一,感覺該剁手了。 。
很多同學在學習JavaScript的時候,可能會聽到「各種各樣」的作用域
什麼詞法作用域、靜態作用域、動態作用域、函數作用域、塊作用域
傻傻分不清楚
下面我就給大家理清一下思緒
作用域的工作模式分為兩種,靜態作用域與動態作用域
其中靜態作用域包括函數作用域和塊作用域
可能同學要問那麼詞法作用域呢
其實詞法作用域和靜態作用域是同一個東西
圖作的不好,大家懂我的意思就好
理清了這一點,我們再來細說
還要補充一個問題,那就是JavaScript中到底有沒有動態作用域?
關於這一點,我在我曾經讀過的兩本書中得到了完全相反的答案
#無論是with語句還是try-catch語句的catch子句,或是包含eval()的函數,都被認為是動態作用域。動態作用域只存在於程式碼執行過程中,因此無法透過靜態分析(查看程式碼結構)偵測出來。 ——《高效能JavaScript》 /p24
要明確的是,事實上JavaScript並不具有動態作用域。它只有詞法作用域,簡單明了。但是this機制某種程度上很像動態作用域。 ——《你不知道的JavaScript(上卷)》 /p59
這兩本書都是很新的書,並且都是非常權威的書,強力推薦
特別是《你不知道的JavaScript》系列,上個月中卷剛出的時候我就迫不及待從網上買了一本
果然沒讓我失望
咳咳扯遠了,回到正題
我想原書的作者大神們,對於動態作用域的理解不一樣
所以才會造成這看似矛盾的觀點
在這裡我想談談我的立場
透過我理解的,我也認為JavaScript中沒有動態作用域
關於靜態、動態作用域有什麼區別
往下看↓
我先上一段程式碼
function foo(){ var a = 1; bar(); }function bar(){ console.log(a); }var a = 100; foo();
透過我們對預編譯、作用域的深入理解
在我們JavaScript的詞法作用域中最後結果列印100
但是如果我們的作用域是動態作用域的話,印出來的就變成了1
這是為什麼呢?
詞法作用域最重要的特點是它的定義過程發生在書寫階段(如果沒有使用eval()和with)
動態作用域使作用域在運行時被動態的決定
詞法作用域關心函數在何處聲明,作用域鏈基於作用域嵌套
動態作用域關心函數在何處調用,作用域鏈基於調用棧
我把上面的話翻譯到程式碼上就是
詞法作用域:因為bar函數是在全域宣告的,所以我輸出全域的變數a的值
動態作用域:因為bar函數是在foo函數內呼叫的,所以我輸出foo內的變數a的值
這就是我的理解
我現在接觸過的程式語言有限,全部都是詞法作用域,我還沒見過基於動態作用域的語言
C、C++、C#、Java、JavaScript、php這些都是詞法作用域
其中JavaScript和php基於函數作用域,其他的基於區塊作用域
在我的理解中
函數作用域就是函數程式碼區塊產生作用域,區塊作用域就是大括號程式碼區塊產生作用域
看到很多部落格中是這麼寫的,JavaScript只有函數作用域(大錯特錯)
這是完全不正確的,沒有爭議
JavaScript確實是基於函數作用域的,但不代表我們沒有塊作用域
特例還真不少,有with關鍵字、try-catch語句的catch子句、let關鍵字(ES6)、const關鍵字(ES6)
這裡我只是簡單的說一下
關鍵字with和catch子句都可以產生區塊作用域
這一點我在一篇文章中寫的應該是很詳細了
感興趣的同許多可以去看看
傳送門–>JavaScript欺騙詞法的eval、with與catch及其效能問題
let關鍵字和var很像,都是宣告變數的,不過let關鍵字可以將變數綁定到所在的任意作用域中
而且使用let進行宣告不會在區塊作用域中進行提升
const關鍵字同樣是宣告變量,不過它宣告的是常數,同樣綁定變數到區塊作用域
這簡直和我們在C/C++的const關鍵字一樣
關於更多的我以後寫到ES6的知識時再詳細說吧
現在我們只需要知道「JavaScript中是有區塊作用域的」就可以了
像平常一樣,跟大家總結一下
作用域工作模式:詞法/靜態作用域,動態作用域
詞法作用域:函數作用域、區塊作用域
JavaScript沒有動態作用域
JavaScript有區塊作用域
with、catch子句、let(ES6)、const(ES6)產生區塊作用域
詞法作用域關心函數在何處宣告
動態作用域關心函數在何處呼叫
詞法作用域作用域鏈基於作用域巢狀
#動態作用域作用域鏈是基於呼叫堆疊
以上就是理清JS中的詞法、靜態、動態、函數、區塊作用域的內容,更多相關內容請關注PHP中文網(www.php.cn)!