執行環境 描述 執行環境 :定義了變數和函數以及其他可以訪問的數據。 每個 執行環境 都有與之對應的 變數對象 ,保存著環境中定義的各種 變數 和 函數 。 解析器 在處理的時候會用到,但是我們的代碼無法訪問。 在瀏覽器雲運行的時候會創建 執行環境 ,調用函數時會創建 執行環境 。 分類 執行環境分 ...
執行環境
描述
- 執行環境:定義了變數和函數以及其他可以訪問的數據。
- 每個執行環境都有與之對應的變數對象,保存著環境中定義的各種變數和函數。解析器在處理的時候會用到,但是我們的代碼無法訪問。
- 在瀏覽器雲運行的時候會創建執行環境,調用函數時會創建執行環境。
分類
執行環境分成兩種類型。
全局執行環境
是最外層的執行環境,在瀏覽器環境中,就是window對象。函數執行環境
每個函數都有自己的執行環境,每進入一個函數時,函數的執行環境就被推到一個環境棧中。在函數執行完以後,這個執行環境會彈棧。
作用域鏈
全局\局部作用域
與全局執行環境、函數執行環境的對應的,這裡有全局作用域、局部作用域的概念。
- 全局作用域:可以在代碼的任何地方進行訪問。
- 局部作用域:一般僅在固定的代碼片段內可以進行訪問。
作用域鏈
其實,全局與局部作用域的訪問許可權,是由作用域鏈決定的。
為了搜索變數、函數,每進入一個新的執行環境都會創建一個作用域鏈。作用域鏈會保存,函數定義環境的(也就是當前函數的外層)有權訪問的的變數和函數,
如下圖所示。
作用域鏈的最前端始終是當前執行的代碼所在環境的變數對象(如果該環境是函數,則將其活動對象作為變數對象),下一個變數對象來自包含環境(包含當前還行環境的環境),下一個變數對象來自包含環境的包含環境,依次往上,直到全局執行環境的變數對象。全局執行環境的變數對象始終是作用域鏈中的最後一個對象。
標識符解析是沿著作用域一級一級的向上搜索標識符的過程。搜索過程始終是從作用域的前端逐地向後回溯,直到找到標識符(找不到,就會導致錯誤發生)。
函數的局部環境可以訪問函數作用域中的變數,也可以訪問和操作父環境(包含環境)乃至全局環境中的變數。
父環境只能訪問包含其的環境和自己環境中的變數和函數,不能訪問其子環境中的變數和函數。
全局環境只能訪問全局環境中的變數和函數,不能直接訪問局部環境中的任何數據。
閉包
其實,函數的局部環境可以訪問函數作用域中的變數,就是閉包。
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(){
}