NFH.016 - Javascript作用域和作用域鏈


2.25學習經驗分享#

Bruce_Zhu于2017.2.25


一、JavaScript作用域

任何程序設計語言都有作用域的概念,簡單的說,作用域就是變量與函數的可訪問范圍,即作用域控制著變量與函數的可見性和生命周期。在JavaScript中,變量的作用域有全局作用域和局部作用域兩種。

1. 全局作用域(Global Scope)

在代碼中任何地方都能訪問到的對象擁有全局作用域,一般來說一下幾種情形擁有全局作用域:

(1)最外層函數和在最外層函數外面定義的變量擁有全局作用域,例如:
<pre>
var authorName="Burce_zxy";
function doSomething(){
var blogName="旅行的意義zxy";
function innerSay(){
alert(blogName);
}
innerSay();
}
alert(authorName); //Bruce_zxy
alert(blogName); //腳本錯誤
doSomething(); //旅行的意義zxy
innerSay() //腳本錯誤
</pre>

(2)所有末定義直接賦值的變量自動聲明為擁有全局作用域,例如:

<pre>
function doSomething(){
var authorName="Bruce_zxy";
blogName="旅行的意義zxy";
alert(authorName);
}
alert(blogName); //旅行的意義zxy
alert(authorName); //腳本錯誤
</pre>

變量blogName擁有全局作用域,而authorName在函數外部無法訪問到。

(3)所有window對象的屬性擁有全局作用域

一般情況下,window對象的內置屬性都都擁有全局作用域,例如window.name、window.location、window.top等等。

2. 局部作用域(Local Scope)

和全局作用域相反,局部作用域一般只在固定的代碼片段內可訪問到,最常見的例如函數內部,所有在一些地方也會看到有人把這種作用域成為函數作用域,例如下列代碼中的blogName和函數innerSay都只擁有局部作用域。

<pre>
function doSomething(){
var blogName="旅行的意義zxy";
function innerSay(){
alert(blogName);
}
innerSay();
}
alert(blogName); //腳本錯誤
innerSay(); //腳本錯誤
</pre>

二、作用域鏈(Scope Chain)

在JavaScript中,函數也是對象,實際上,JavaScript里一切都是對象。函數對象和其它對象一樣,擁有可以通過代碼訪問的屬性和一系列僅供JavaScript引擎訪問的內部屬性。其中一個內部屬性是[[Scope]],由ECMA-262標準第三版定義,該內部屬性包含了函數被創建的作用域中對象的集合,這個集合被稱為函數的作用域鏈,它決定了哪些數據能被函數訪問。

當一個函數創建后,它的作用域鏈會被創建此函數的作用域中可訪問的數據對象填充。例如定義下面這樣一個函數:

<pre>
function add(num1,num2) {
var sum = num1 + num2;
return sum;
}
</pre>
在函數add創建時,它的作用域鏈中會填入一個全局對象,該全局對象包含了所有全局變量。如下圖所示(注意:圖片只例舉了全部變量中的一部分):

全局變量

函數add的作用域將會在執行時用到。例如執行如下代碼:

<pre>
var total = add(5,10);
</pre>
執行此函數時會創建一個稱為“運行期上下文(execution context)”的內部對象,運行期上下文定義了函數執行時的環境。每個運行期上下文都有自己的作用域鏈,用于標識符解析,當運行期上下文被創建時,而它的作用域鏈初始化為當前運行函數的[[Scope]]所包含的對象。

這些值按照它們出現在函數中的順序被復制到運行期上下文的作用域鏈中。它們共同組成了一個新的對象,叫“活動對象(activation object)”,該對象包含了函數的所有局部變量、命名參數、參數集合以及this,然后此對象會被推入作用域鏈的前端,當運行期上下文被銷毀,活動對象也隨之銷毀。新的作用域鏈如下圖所示:

新作用域鏈

在函數執行過程中,沒遇到一個變量,都會經歷一次標識符解析過程以決定從哪里獲取和存儲數據。該過程從作用域鏈頭部,也就是從活動對象開始搜索,查找同名的標識符,如果找到了就使用這個標識符對應的變量,如果沒找到繼續搜索作用域鏈中的下一個對象,如果搜索完所有對象都未找到,則認為該標識符未定義。函數執行過程中,每個標識符都要經歷這樣的搜索過程。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容