做用域
用來聲明,訪問和修改變量的上下文,定義了變量的訪問權限和查找機制。javascript
做用域分類:java
- 全局做用域 (整個JS運行環境,最頂層做用域,其聲明的函數、變量等都是全局的)
- 函數做用域 (函數執行時會建立做用域)
- 塊級做用域 ({ }大括號在 let、const關鍵字特性產生的做用域)
JS屬於編譯語言,逐行執行;編譯的過程分爲三部分:函數
- 分詞/詞法分析。
- 解析/把詞法分析轉換成AST(抽象語法樹)。
- 代碼生成/把AST轉成可執行代碼。
示例:code
var a = 1;
編譯過程:ip
- 分紅var a、a=1;兩部分進行分析。
- 查看當前做用域是否有a,若是有就忽略,若是沒有就建立變量a。
(var、function聲明的變量會在當前做用域下進行變量提高)
- 賦值操做,首先查看當前做用域下是否有變量a,要是不存在變量a就會報錯,要是存在進行賦值;其次若是是做用域嵌套的狀況,當前做用域下不存在變量a,就會向外層做用域查找,直到全局做用域,若是不存在變量a就會報錯。
執行過程:作用域
- 執行var a語句進行查找a變量,這個過程叫作LHS(左側爲查找目標)。
- 執行a = 1賦值操做,過程叫作RHS(右側爲目標查找的目的)。
- 進行RHS必然會進行LHS。
注意:取值和賦值都是RHS,變量聲明和形參是LHS;RHS和LHS發生在執行過程當中。io
示例:編譯
function foo(a) {
var b = a;
return a + b
}
var c = foo(2)
3處LHS查詢:function
- var c 聲明
- var b 聲明
- 形參 a 聲明
4處RHS查詢:class
- foo(2) 取值foo並執行
- var b = a語句,取值a
- a + b語句,取值a
- a + b語句,取值b
做用域嵌套:
當一個塊或函數嵌套在另外一個塊或函數裏,就發生了做用域嵌套。
做用域嵌套下變量的查找規則:
查找變量時若是當前做用域裏沒有找到,就會向外層做用域查找,直到找到該變量或到全局做用域爲止,若是沒找到就會報錯。
做用域嵌套查找變量的特色:
從內往外,LHS和RHS都會在當前做用域進行,LHS只有當前做用域下沒有找到所需變量,纔會向外層做用域查找。
變量提高對LHS的影響:
- 變量提高發生在編譯過程,一個沒有用var聲明的變量不會進行變量提高,在該變量以前進行RHS,會報ReferenceError異常is not defined。
- 用var聲明的變量會進行變量提高,提高到當前做用域的最頂部,其值是undefined,所以在變量前進行取值不會報錯。
- 非嚴格模式下對沒有用var關鍵字聲明的變量語句以前進行RHS,報ReferenceError異常。若是是以後進行RHS,會先進行LHS,若是當前做用域仍是全局做用域下都沒有找到,會自動建立一個全局變量並返回,嚴格模式下LHR查詢失敗時,並不會建立一個全局變量並返回,報ReferenceError異常。
變量的訪問權限問題:
- 塊級做用域裏的變量外層做用域是沒法訪問,變量是指由let,const。
- 函數的形參和變量,內部函數是外層做用域沒法訪問,屬於局部變量。變量是指由let,const,var,function聲明的。
部分參考:
《你不知道的JavaScript》