# 执行上下文与执行上下文栈

# 变量提升

  1. 变量声明提升
    • 通过 var 定义(声明)的变量,在定义语句之前就可以访问到
    • 值: undefined
  2. 函数声明提升
    • 通过 function 声明的函数,在之前就可以直接调用
    • 值:函数定义(对象)
  3. 变量提升和函数提升是如何产生的
var a = 3
function fn() {
    console.log(a)
    var a = 4
}
fn() // undefined

fn2() // fn2
fn3() // error fn3 is not a function

function fn2() {
    console.log('fn2')
}

var fn3 = function() {
    console.log('fn3')
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 执行上下文

  1. 代码分类

    根据位置分类

    • 全局代码
    • 函数(局部)代码
  2. 全局执行上下文

    • 在执行全局代码前将 window 确定为全局执行上下文
    • 对全局数据进行预处理
      • var 定义的全局变量 ==> undefined,添加为 window 的属性
      • function 声明的全局函数 ==> 赋值(fun),添加为 window 的方法
      • this ==> 赋值 window
    • 开始执行全局代码
  3. 函数执行上下文

    • 调用函数,准备执行函数体之前,创建对应的函数执行上下文对象(虚拟存在于栈中)
    • 对局部数据进行预处理
      • 形参变量 ==> 赋值(实参)==> 添加为执行上下文的属性
      • arguments ==> 赋值(实参列表),添加为执行上下文的属性
      • var 定义的局部变量 ==> undefined,添加为执行上下文的属性
      • function 声明的函数 ==> 赋值(fun),添加为执行上文的方法
      • this ==> 赋值(调用函数的对象)
    • 开始执行函数体代码
// 全局执行上下文
console.log(a, window.a) // undefined undefined
window.fn() // fn
console.log(this) // window

var a = 2
function fn() {
    console.log('fn')
}

// 函数执行上下文
function func(a) {
    console.log(a) // 2
    console.log(fn) // function fn()
    b() // b()
    console.log(this) // window
    console.log(arguments) // 伪数组[2, 3]
    
    var n = 3
    function b() {
        console.log('b()')
    }
}

func(2, 3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 执行上下文栈

  1. 在全局代码执行前,JS引擎就会创建一个栈来存储管理所有的执行上下文对象
  2. 在全局执行上下文(window)确定后,将其添加到栈中(压栈)
  3. 在函数执行上下文创建后,将其添加到栈中(压栈)
  4. 在当前函数执行完后,将栈顶的对象移除(出栈)
  5. 当所有的代码执行完后,栈中只剩下 window
// 1. 进入全局执行上下文
var a = 10
var fun = function(x) {
    var b = 5
    foo(x + b) // 3. 进入foo函数执行上下文
}

var foo = function(y) {
    var c = 5
    console.log(a + c + y)
}

fun(10) // 2. 进入fun函数执行上下文
1
2
3
4
5
6
7
8
9
10
11
12
13

console.log(i) // undefined
var i = 1
foo(1) // 1, 2, 3, fe: 3, fe: 2, fe: 1
function foo(i) {
    if (i === 4) {
        return
    }
    console.log('foo:' + i)
    foo(i + 1) // 递归调用:在函数内部调用自己
    console.log('fe:' + i)
}
console.log(i) // 1
1
2
3
4
5
6
7
8
9
10
11
12

栈执行顺序

function a() {}
var a;
console.log(typeof a) // 'function' 先执行变量提升,再执行函数提升

if (!(b in window)) {
    var b = 1
}
console.log(b) // undefined

var c = 1
function c(c) {
    console.log(c)
}
c(2) // error c is not a function
/**
var c;
fuction c(){}
c = 1
c()
**/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
更新于: 3/11/2020, 8:57:26 AM