1 一个执行上下文的生命周期可以分为两个阶段:
- 创建阶段
- 执行上下文会分别 创建变量对象,建立作用域链,以及确定 this 指向。
- 代码执行阶段
- 创建完成之后,就会开始执行代码,会完成变量赋值,函数引用,以及执行其他代码。
创建(生成变量对象、建立作用域链、确定this指向) -------》 执行(变量赋值、函数引用、执行其他代码) -------执行完毕后出栈,等待被回收-------》
2 变量对象的创建,依次经历了以下几个过程:
- 建立 arguments 对象:检查当前上下文中的参数,建立该对象下的 属性 与 属性值。(函数参数)
- 检查当前上下文的函数声明,也就是使用 function 关键字声明的函数。在变量对象中以函数名建立一个属性,属性值为指向该函数所在内存地址的引用。
- 检查当前上下文中的变量声明,每找到一个变量声明,就在变量对象中以变量名建立一个属性,属性值为 undefined。
如果变量与函数同名,则在这个阶段,以函数值为准。
变量对象创建过程:
创建 arguments 对象 -------》 检查 function 函数声明创建属性 -------》 检查 var 变量声明创建属性
function 声明会比 var 声明优先级更高一点
执行上下文未进入执行阶段之前,变量对象中的属性都不能访问!但是进入执行阶段之后,变量对象转变为了活动对象,里面的属性都能被访问了,然后开始进行执行阶段的操作。
3 全局上下文的变量对象
以浏览器中为例,全局对象为 window。 全局上下文有一个特殊的地方,它的变量对象,就是 window 对象。而这个特殊,在 this 指向上也同样适用,this 也是指向 window。
// 以浏览器中为例,全局对象为window
// 全局上下文
windowEC = {
VO: Window,
scopeChain: {},
this: Window
}
全局上下文的生命周期,与程序的生命周期一致,只要程序运行不结束,比如关掉浏览器窗口,全局上下文就会一直存在。其他所有的上下文环境,都能直接访问全局上下文的属性。
4 let/const
let/const 声明的变量,仍然会提前被收集到变量对象中,但和 var 不同的是,let/const 定义的变量,不会在这个时候给他赋值undefined。
因为完全没有赋值,即使变量提升了,我们也不能在赋值之前调用他。这就是我们常说的暂时性死区。