01. 變數提升與函數提升 1. 變數聲明提升* 通過var定義(聲明)的變數, 在定義語句之前就可以訪問到* 值: undefined2. 函數聲明提升* 通過function聲明的函數, 在之前就可以直接調用* 值: 函數定義(對象)3. 問題: 變數提升和函數提升是如何產生的? 02. 執行上 ...
01. 變數提升與函數提升
1. 變數聲明提升
* 通過var定義(聲明)的變數, 在定義語句之前就可以訪問到
* 值: undefined
2. 函數聲明提升
* 通過function聲明的函數, 在之前就可以直接調用
* 值: 函數定義(對象)
3. 問題: 變數提升和函數提升是如何產生的?
// 面試題: 輸出什麼? var a = 4 function fn1() { console.log(a) } function fn2() { console.log(a) var a = 5 } function fn3(a) { console.log(a) } function fn4(a) { console.log(a) var a = 5 } fn1() // 4 fn1(1) // 4 fn2() // undefined fn2(1) // undefined fn3() // undefined fn3(1) // 1 fn4() // undefined fn4(1) // 1 /*變數提升*/ console.log(a1) //可以訪問, 但值是undefined var a1 = 3 /*函數提升*/ a2() // 可以直接調用 function a2() { console.log('a2()') }
02. 執行上下文
1. 代碼分類(位置)
* 全局代碼
* 函數代碼
2. 全局執行上下文
* 在執行全局代碼前將window確定為全局執行上下文
* 對全局數據進行預處理
* var定義的全局變數==>undefined, 添加為window的屬性
* function聲明的全局函數==>賦值(fun), 添加為window的方法
* this==>賦值(window)
* 開始執行全局代碼
3. 函數執行上下文
* 在調用函數, 準備執行函數體之前, 創建對應的函數執行上下文對象
* 對局部數據進行預處理
* 形參變數==>賦值(實參)==>添加為執行上下文的屬性
* arguments==>賦值(實參列表), 添加為執行上下文的屬性
* var定義的局部變數==>undefined, 添加為執行上下文的屬性
* function聲明的函數 ==>賦值(fun), 添加為執行上下文的方法
* this==>賦值(調用函數的對象)
* 開始執行函數體代碼
console.log(a1) // undefined console.log(a2) // undefined console.log(a3) // fun // console.log(a4) // error a4 is not defined console.log(this) // window var a1 = 3 var a2 = function () { console.log('a2()') } function a3() { console.log('a3()') } a4 = 4 function fn(x, y) { console.log(x, y) // undefined undefined console.log(b1) // undefined console.log(b2) // fun console.log(arguments) // arguments console.log(this) // window // console.log(b3) // error b3 is not defined var b1 = 5 function b2 () {} b3 = 6 } fn()
03. 執行上下文棧
1. 在全局代碼執行前, JS引擎就會創建一個棧來存儲管理所有的執行上下文對象
2. 在全局執行上下文(window)確定後, 將其添加到棧中(壓棧)
3. 在函數執行上下文創建後, 將其添加到棧中(壓棧)
4. 在當前函數執行完後,將棧頂的對象移除(出棧)
5. 當所有的代碼執行完後, 棧中只剩下window
//1. 進入全局執行上下文 var a = 10 var bar = function (x) { var b = 5 foo(x + b) //3. 進入foo執行上下文 } var foo = function (y) { var c = 5 console.log(a + c + y) } bar(10) //2. 進入bar函數執行上下文
04. 執行上下文棧2
1. 依次輸出什麼?
2. 整個過程中產生了幾個執行上下文?
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); // global begin: undefined // foo() begin:1 // foo() begin:2 // foo() begin:3 // foo() end:: 3 // foo() end:: 2 // foo() end:: 1 // global end: 1
05. 面試題
// 測試題1: 先預處理變數, 後預處理函數 function a() {} var a; console.log(typeof a) // function // 測試題2: 變數預處理, in操作符 if (!(b in window)) { var b = 1; } console.log(b) // undefined // 測試題3: 預處理, 順序執行 var c = 1 function c(c) { console.log(c) var c = 3 } c(2) // c is not a function