window 是最大最外圍的執行環境,然後每個函數都有自己的執行環境。JS代碼是從上到下執行的,單純的用語言描述可能會有點繞,而且不大直觀。我們看著代碼來 上面代碼依次輸出的是什麼? 一進來先是 window 執行環境,然後 window 會把先把裡面的變數和函數提升,然後在從上到下執行。到 foo ...
window 是最大最外圍的執行環境,然後每個函數都有自己的執行環境。JS代碼是從上到下執行的,單純的用語言描述可能會有點繞,而且不大直觀。我們看著代碼來
console.log('global begin:' + i); var i = 1 foo(1) function foo(i){ if(i == 4){ return } console.log('foo() begin:' + i); foo(i+1) console.log('foo() end:' + i); } console.log('global end:' + i);
上面代碼依次輸出的是什麼?
一進來先是 window 執行環境,然後 window 會把先把裡面的變數和函數提升,然後在從上到下執行。到 foo(1)時 會創建一個 foo的執行環境,然後就會去執行函數,在這應該都沒有問題。 當 i= 3的時候執行的是 foo(4)滿足條件,直接退出。執行
console.log('foo() end:' + i); // 3 重點就在這為什麼是 3
就是這個執行環境在作怪,每次調用函數都會創建一個執行上下文環境,並把這個執行函數推進了棧裡面,只有這個函數完全執行完畢了這個環境才會被釋放的,因為之前的函數並沒有執行完
console.log('foo() end:' + i); 這個還沒有執行,所以他們會被一直保存在棧中。棧有一個特點就是後進先出
這個就是執行 foo(4)時的棧,foo(4)執行完了被釋放,我們就執行foo(3)剩餘的東西,直到把 foo 函數都執行完,棧裡面就只剩下 window 了。只有關閉瀏覽器視窗的時候window才會被釋放。
作用域鏈:其實每個執行環境都對應了一個變數對象,這個變數對象中就保存了當前環境中定義的所有變數和函數。當代碼在一個環境中執行的時候就會創建變數對象的一個作用域鏈。如果是函數,他的對象是活動對象,最開始的時候只包含了一個 arguments ,他的作用域鏈中的下一個變數對象就是包含他的環境,就這樣一層一層下去,直到最底層的 window
能力有限,表達的可能不是很清楚,如果有什麼不對的請指正