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

176 阅读2分钟

1)代码分类(位置)

  • 全局代码
  • 函数(局部)代码

2)全局执行上下文

在执行全局代码之前,创建执行上下文栈

过程

在执行全局代码之前将顶级对象(window)确定为全局执行上下文,压入执行上下文栈中
对全局数据进行预处理
  • var 定义的全局变量 ==》赋值为undefined,添加为window的属性 (变量提升)
  • function声明的全局函数 =》 赋值,添加为window的方法 (函数提升,注意:只有函数声明式的函数才会存在函数提升)
  • this =》 赋值为window
开始执行全局代码

3)函数执行上下文

在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象,压入执行上下文栈中(虚拟对象,存在于栈中,不是真实存在的对象,但可以理解为对象来使用)

对局部数据进行预处理

  • 形参变量 ==》 赋值(实参)==》添加为执行上下文的属性
  • arguments ==》(赋值实参列表),添加为执行上下文的属性
  • var定义的局部变量 ==》 undefined,添加为执行上下文的属性(变量提升)
  • function声明的函数 ==》 赋值,添加为执行上下文的方法(函数提升)
  • this ==》 (赋值调用函数的对象

开始执行函数体代码

4)执行上下文栈

在执行全局代码前,JS引擎就会创建一个栈来存储管理所有的执行上下文对象

在全局执行上下文(window)确定后,将其添加到栈中(压栈)

在函数执行上下文创建后,将其添加到栈中(压栈)

在当前函数执行完后,将栈顶的对象移除(出栈)

当所有的代码执行完后,栈中只剩下window

5)产生多少个执行上下文

n + 1个,n为调用函数的次数,1为window

5)小结

可以看出变量提升与函数提升是执行上下文与执行上下文栈的结果

变量提升
  • 只针对var定义的变量存在变量提升
    • 变量提升只是一种结果,本质过程是在创建上下文对象时(编译阶段)能够识别到var和let等声明的变量,但var定义的变量会初始化为undefined,而let定义的变量不会初始化为undefined,仍处于未初始化状态,因此会报错:未初始化;
      • let声明的变量在赋初值之前,因为没有初始化,故如果访问的话会报错,即暂时性死区现象
  • 在变量定义之前就能访问这个变量,值为undefined
函数提升
  • 函数定义语句之前就可以调用执行这个函数
变量提升的优先级高于函数提升,即变量提升先于函数提升