1. 程式人生 > >深入理解JavaScript變數作用域

深入理解JavaScript變數作用域

首先需要提一下JavaScript的提前宣告.

所謂的提前宣告,指的是一個變量在被宣告的時候,JavaScript在被宣告的時候,JavaScript會自動地把它放到程式碼塊的最頂部,也就是說,在這個變數定義的程式碼塊裡,你甚至可以把呼叫這個變數的語句放在宣告之前,不過此時變數的賦值會是undefined

示例程式碼:


執行結果:

上面的程式碼和下面的程式碼是等價的

事實上JavaScript對於變數的提前宣告的操作也確實如此

關於JavaScript的變數作用域

JavaScript的變數按照作用域劃分,一共可分為兩種,一種叫全域性變數,另

一種叫做區域性變數,首先需要宣告,我們在討論全域性變數和區域性變數的時候,真正在討論的其實是全域性作用域和區域性作用域,全域性變數作用在全域性作用域,區域性變數作用在區域性作用域

      全域性變數顧名思義,就是在程式碼的全域性都可以呼叫的變數.全域性變數定義在最外層函式或者程式碼的最外層,或者不使用var,const,let定義直接賦值的變數,比如a=1;b=’asd’;c=[1,2,3]等都屬於全域性變數.與之相對的,定義在函式體內部的變數屬於區域性變數

      因為作用域的原因,全域性變數在定義了同名區域性變數的函式體內無法直接呼叫,函式體內定義的同名區域性變數會暫時遮蔽這個全域性變數(原理下面會講).但是可以通過關鍵字window來呼叫,其原因是全域性變數的定義都處於最外層物件window之內,每定義一個全域性變數,都相當於給window物件新加了一個屬性,例如定義全域性變數var i=0;這就相當於給window物件新加了一個i屬性,其屬性值為0,這樣的話,在函式體內自然就可以通過呼叫window物件的屬性來呼叫全域性變數,也就是通過window.i來呼叫全域性變數i

作用域鏈

      每段js程式碼(包括全域性程式碼和函式)在定義的時候,都會相應的被賦予一個作用域鏈,他是一個物件列表或者連結串列.全域性程式碼的作用域鏈裡只有一個全域性作用域,這就造成了他不能呼叫區域性作用域裡定義的變數,函式體的作用域鏈裡既有屬於這個函式的區域性作用域,也有全域性作用域.當這個函式內部還定義了其他函式的時候,被巢狀的這個函式的作用域不僅有屬於他的區域性作用域和全域性作用域,還有巢狀他的函式的區域性作用域,以此類推

      當函式內的一個變數要被呼叫的時候,函式會從離他最近一個作用域或者物件開始尋找這個變數,當在這個作用域找到了,此時就會直接呼叫這個變數.若沒找到,就進入上一級作用域繼續尋找,直到找到這個變數.如果找遍了他的作用域鏈內的所有作用域和物件都沒有找到這個變數,此時會丟擲ReferenceError異常

不同層級作用域上物件的分佈:

JavaScript最頂層:作用域由一個全域性物件組成

不包含巢狀的函式體內部:作用域由一個屬於該函式的區域性作用域和全域性物件組成

在一個巢狀的函式體內:作用域鏈內至少包含三個物件:他自己的作用域,父級函式的作用域以及一個全域性物件

每當呼叫一個函式的時候,屬於他的區域性作用域都會被重新建立,若想儲存下這個區域性作用域,可以使用閉包操作,但這不是這篇文章需要介紹的,有興趣瞭解的請移步王福朋的博文深入理解JavaScript原型和閉包(完結)-王福朋