變量提升與函數提升
變量聲明提升
通過var定義(聲明)的變量, 在定義語句之前就可以訪問到
值: undefined
函數聲明提升
通過function聲明的函數, 在之前就可以直接調用
值: 函數定義(對象)
面試題 :
var a = 3
function fn () {
console.log(a)
var a = 4
}
fn() // undefined
console.log(b) //undefined 變量提升
fn2() //可調用 函數提升
// fn3() //不能 變量提升
var b = 3
function fn2() {
console.log('fn2()')
}
var fn3 = function () {
console.log('fn3()')
}
執行上下文
代碼分類(位置)
全局代碼
函數(局部)代碼
全局執行上下文
在執行全局代碼前將window確定爲全局執行上下文
對全局數據進行預處理
var定義的全局變量==>undefined, 添加爲window的屬性
function聲明的全局函數==>賦值(fun), 添加爲window的方法
this==>賦值(window)
開始執行全局代碼
函數執行上下文
在調用函數, 準備執行函數體之前, 創建對應的函數執行上下文對象(虛擬的, 存在於棧中)
對局部數據進行預處理
* 形參變量==>賦值(實參)==>添加爲執行上下文的屬性
* arguments==>賦值(實參列表), 添加爲執行上下文的屬性
* var定義的局部變量==>undefined, 添加爲執行上下文的屬性
* function聲明的函數 ==>賦值(fun), 添加爲執行上下文的方法
* this==>賦值(調用函數的對象)
開始執行函數體代碼
執行上下文棧
理解
棧 :後進先出
隊列:先進先出
1. 在全局代碼執行前,
JS引擎就會創建一個棧來存儲管理所有的執行上下文對象
2. 在全局執行上下文(window)確定後, 將其添加到棧中(壓棧)
3. 在函數執行上下文創建後, 將其添加到棧中(壓棧)
4. 在當前函數執行完後,將棧頂的對象移除(出棧)
5. 當所有的代碼執行完後, 棧中只剩下window
流程分析
測試題
1. 依次輸出什麼?
console.log('gb: '+ i)
var i = 1
foo(1)
function foo(i) {
if (i == 4) {
return
}
console.log('fb:' + i)
foo(i + 1) //遞歸調用: 在函數內部調用自己
console.log('fe:' + i)
}
console.log('ge: ' + i)
gb: undefined
fb: 1
fb: 2
fb: 3
fe: 3
fe: 2
fe: 1
ge: 1
面試題
測試題1
function a() {}
var a;
console.log(typeof a)
// function
測試題2
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
<=>
var c
function c(c) {
console.log(c)
var c = 3
}
c = 1
c(2)