执行上下文与执行上下文栈
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
函数提升
变量提升的优先级高于函数提升,即变量提升先于函数提升