变量对象(Variable Object,VO)用于记录在当前作用域中可以访问到的所有变量。
变量对象的创建
在执行上下文的创建阶段,除了执行上下文自身被创建外,同时其内部会分别创建变量对象(VO)、建立作用域链(SC),以及确定 this 的指向(之前确定好的作用域也会添加进来)。
而变量对象在创建过程中也分为了三个阶段:
- 检查当前作用域中的函数参数:建立 arguments 对象,将形参和实参作为该对象下的属性名与属性值。
- 检查当前作用域中的声明式函数:以函数名建立一个属性,属性值为该函数所在内存地址的引用。如果函数名的属性已经存在,那么该属性将会被新的引用所覆盖。
- 检查当前作用域中
var
声明的变量:以变量名建立一个属性,属性值为undefined
。如果该变量名的属性已经存在,为了防止同名的函数被修改为undefined
,则会直接跳过,原属性值不会被修改。
图解分析:
代码分析:
|
|
在全局代码outer(10)
执行时,outer 函数被调用,产生局部上下文,同时其内部的变量对象也开始创建。为了便于理解,我们通过伪代码的形式来表示一下:
|
|
活动对象
执行上下文未进入“代码执行阶段”前,变量对象中的属性都不能访问。一旦进入“代码执行阶段”,变量对象就会转换为活动对象(Active Object,AO),而活动对象中的属性就可以进行访问了。
说明:变量对象和活动对象其实就是同一个对象,只是处于执行上下文不同的阶段有不同的名字。
因此,当上面的例子进入“代码执行阶段”后,变量对象转换为活动对象,伪代码如下所示:
|
|
因此,当console.log()
语句执行时,就会去变量对象中查询对应的数据并输出。其实”变量提升”和”函数提升”这两个概念的本质就是变量对象的创建过程。
总结
- 变量对象是在执行上下文建立阶段产生的。
- 变量对象的建立分为了三个过程:查找参数、查找声明式函数、查找
var
变量。 - 变量对象中的属性不能进行任何操作。
- 变量对象在执行上下文激活阶段时变为活动对象,其内部属性才可以进行操作。