03. 函數高級-執行上下文與執行上下文棧

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. 整個過程當中產生了幾個執行上下文?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

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
相關文章
相關標籤/搜索