1. 程式人生 > >作用域那點事

作用域那點事

## 作用域 > 用來宣告,訪問和修改變數的上下文,定義了變數的訪問許可權和查詢機制。 作用域分類: - 全域性作用域 (整個JS執行環境,最頂層作用域,其宣告的函式、變數等都是全域性的) - 函式作用域 (函式執行時會建立作用域) - 塊級作用域 ({ }大括號在 let、const關鍵字特性產生的作用域) JS屬於編譯語言,逐行執行;編譯的過程分為三部分: - 分詞/詞法分析。 - 解析/把詞法分析轉換成AST(抽象語法樹)。 - 程式碼生成/把AST轉成可執行程式碼。 示例: ``` javascript var a = 1; ``` 編譯過程: - 分成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發生在執行過程中。 示例: ``` function foo(a) { var b = a; return a + b } var c = foo(2) ``` 3處LHS查詢: - var c 宣告 - var b 宣告 - 形參 a 宣告 4處RHS查詢: - 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宣告的。 部分參考: 《你不知道的JavaSc