做用域那點事

做用域

用來聲明,訪問和修改變量的上下文,定義了變量的訪問權限和查找機制。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》

相關文章
相關標籤/搜索