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()') }
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()
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函數執行上下文
1. 依次輸出什麼?
2. 整個過程當中產生了幾個執行上下文?this
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
// 測試題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