JavaScript做用域鏈

執行環境

描述

  • 執行環境:定義了變量和函數以及其餘能夠訪問的數據。
  • 每一個執行環境都有與之對應的變量對象,保存着環境中定義的各類變量函數解析器在處理的時候會用到,可是咱們的代碼沒法訪問。
  • 在瀏覽器雲運行的時候會建立執行環境,調用函數時會建立執行環境

分類

執行環境分紅兩種類型。html

  1. 全局執行環境
    是最外層的執行環境,在瀏覽器環境中,就是window對象。前端

  2. 函數執行環境
    每一個函數都有本身的執行環境,每進入一個函數時,函數的執行環境就被推到一個環境棧中。在函數執行完之後,這個執行環境會彈棧。瀏覽器

做用域鏈

全局\局部做用域

全局執行環境函數執行環境的對應的,這裏有全局做用域局部做用域的概念。閉包

  • 全局做用域:能夠在代碼的任何地方進行訪問。
  • 局部做用域:通常僅在固定的代碼片斷內能夠進行訪問。

做用域鏈

其實,全局與局部做用域的訪問權限,是由做用域鏈決定的。
爲了搜索變量、函數,每進入一個新的執行環境都會建立一個做用域鏈做用域鏈會保存,函數定義環境的(也就是當前函數的外層)有權訪問的的變量和函數,
以下圖所示。函數

  • 做用域鏈的最前端始終是當前執行的代碼所在環境的變量對象(若是該環境是函數,則將其活動對象做爲變量對象),下一個變量對象來自包含環境(包含當前還行環境的環境),下一個變量對象來自包含環境的包含環境,依次往上,直到全局執行環境的變量對象。全局執行環境的變量對象始終是做用域鏈中的最後一個對象。3d

  • 標識符解析是沿着做用域一級一級的向上搜索標識符的過程。搜索過程始終是從做用域的前端逐地向後回溯,直到找到標識符(找不到,就會致使錯誤發生)。code

  • 函數的局部環境能夠訪問函數做用域中的變量,也能夠訪問和操做父環境(包含環境)乃至全局環境中的變量。htm

  • 父環境只能訪問包含其的環境和本身環境中的變量和函數,不能訪問其子環境中的變量和函數。對象

  • 全局環境只能訪問全局環境中的變量和函數,不能直接訪問局部環境中的任何數據。blog

閉包

其實,函數的局部環境能夠訪問函數做用域中的變量,就是閉包。

function a(){
    let xxx = 1;
    log();
    function log(){
        console.log(xxx);
    }
}

提高(hoisting)

變量提高

var a = 1;
c();
function c(){
   console.log(a);   // undefined
   var a = 2; 
}

解析器在函數執行環境中發現變量a,所以再也不上層查找。可是console.log(a)時還未賦值,因此打印undefined。上面的代碼等價於:

var a = 1;
c();
function c(){
   var a;
   console.log(a);   // undefined
   a = 2; 
}

這種現象就是變量提高
注意,上面這段代碼若是var改爲let

let a = 1;
c();
function c(){
   console.log(a);   // 報錯
   let a = 2; 
}

此時,會造成暫時性死區,let在預解析過程當中不會被提高。

函數提高

c()
function c(){
    //...
}

函數在預解析過程當中也會發生提高現象。
注意:只有函數聲明形式才能被提高!!

c(); //會報錯
var c = function(){

}

參考文獻

相關文章
相關標籤/搜索