在理解做用域鏈以前先要知道執行環境。任何函數都有一個執行環境,最外圍的是全局執行環境,每個環境都有本身的活動對象,活動對象裏面存在的是當前環境中的變量。前端
當代碼在一個環境中執行時,會建立變量對象的一個做用域鏈(scope chain)。做用域鏈裏存放的是當前環境以及外部環境的活動對象。做用域鏈的最前端的活動對象始終是當前環境的,下一級就是外部環境,再下一個活動對象來自再下一級的外部環境。當前環境活動對象裏若是沒有包含函數中使用的變量,那麼會沿着做用鏈去找下一個環境中的活動對象,直到全局環境。這樣說可能太晦澀難懂了, 讓咱們分析一段代碼:bash
var a = 1
function fn1(){
function fn2(){
console.log(a)
}
function fn3(){
var a = 4
fn2()
}
var a = 2
return fn3
}
var fn = fn1()
fn() //2
複製代碼
執行fn1其中var a = 2
已經成功定義而且a被賦值2,將fn3賦予了fn而後執行fn也就是執行fn3,在fn3中a被定義並賦值4,而後執行了fn2最終結果是2,說明了fn2是從fn1中的活動對象裏找到的a。
那咱們來看一下圖:函數
var a = 1
function fn1(){
function fn3(){
var a = 4
fn2()
}
var a = 2
return fn3
}
function fn2(){
console.log(a)
}
var fn = fn1()
fn() //1
複製代碼
上面的代碼最終輸出的是1.說明fn2是從全局活動對象裏查找到a的聲明,因此查找順序那咱們應該看聲明fn2的環境,而不是調用fn2的環境。 看圖: ui