js 的初始化順序執行上下文與閉包
阿新 • • 發佈:2018-12-24
- 1. 程式碼分類(位置)
- 全域性程式碼
- 函式(區域性)程式碼
- 2. 全域性執行上下文
- 在執行全域性程式碼前將window確定為全域性執行上下文
- 對全域性資料進行預處理
- var定義的全域性變數==>undefined, 新增為window的屬性
- function宣告的全域性函式==>賦值(fun), 新增為window的方法
- this==>賦值(window)
- 開始執行全域性程式碼
- 3. 函式執行上下文
- 在呼叫函式, 準備執行函式體之前, 建立對應的函式執行上下文物件(虛擬的, 存在於棧中)
- 對區域性資料進行預處理
- 形參變數==>賦值(實參)==>新增為執行上下文的屬性
- arguments==>賦值(實參列表), 新增為執行上下文的屬性
- var定義的區域性變數==>undefined, 新增為執行上下文的屬性
- function宣告的函式 ==>賦值(fun), 新增為執行上下文的方法
- this==>賦值(呼叫函式的物件)
- 開始執行函式體程式碼
var a = 3 function fn () { console.log(a) var a = 4 } fn() console.log(b) //undefined 變數提升 fn2() //可呼叫 函式提升 fn3() //不能 變數提升 var b = 3 function fn2() { console.log('fn2()') } var fn3 = function () { console.log('fn3()') }
總結起來就是先全域性上下文,首先是變數提升給undefined值 , 然後是函式提升。放變數和函式提升以後,按序執行程式碼,還有顯式的變數賦值 ,以下程式碼 c 在變數提升,函式提升之後,又經過顯式賦值,最終仍變會number 型別
var c = 1
function c(c) {
console.log(c)
var c = 3
}
c(2) // 報錯
js初始化順序
- 1. 在全域性程式碼執行前, JS引擎就會建立一個棧來儲存管理所有的執行上下文物件
- 2. 在全域性執行上下文(window)確定後, 將其新增到棧中(壓棧)
- 3. 在函式執行上下文建立後, 將其新增到棧中(壓棧)
- 4. 在當前函式執行完後,將棧頂的物件移除(出棧)
- 5. 當所有的程式碼執行完後, 棧中只剩下window
閉包
-
當一個巢狀的內部(子)函式引用了巢狀的外部(父)函式的變數(函式)時, 就產生了閉包
-
函式巢狀
-
內部函式引用了外部函式的資料(變數/函式)
- 1. 使用函式內部的變數在函式執行完後, 仍然存活在記憶體中(延長了區域性變數的生命週期)
- 2. 讓函式外部可以操作(讀寫)到函式內部的資料(變數/函式)
- 問題:
- 1. 函式執行完後, 函式內部宣告的區域性變數是否還存在? 一般是不存在, 存在於閉中的變數才可能存在
- 2. 在函式外部能直接訪問函式內部的區域性變數嗎? 不能, 但我們可以通過閉包讓外部操作它
- 1. 產生: 在巢狀內部函式定義執行完時就產生了(不是在呼叫)
- 2. 死亡: 在巢狀的內部函式成為垃圾物件時
function fn1() {
//此時閉包就已經產生了(函式提升, 內部函式物件已經建立了)
var a = 2
function fn2 () {
a++
console.log(a)
}
return fn2
}
var f = fn1()
f() // 3
f() // 4
f = null //閉包死亡(包含閉包的函式物件成為垃圾物件)