变量对象
关键字
变量对象(variable object), 活动对象(activation object), 执行上下文
变量对象(variable object)
作用:
每个执行上下文都有一个与之关联的变量对象, 执行上下文中定义的所有变量和函数都保存在这个对象中, 我们无法编码无法访问这个对象,但是解析器会在后台处理它。
在执行上下文一章中我们提到一个执行上下文必定包括:变量对象,作用域链,this对象, 执行上下文又分三种全局上下文,函数上下文,eval上下文。
全局上下文
一句话:在全局上下文中的变量对象就是宿主环境的全局对象。
宿主环境?说的简单点儿就是:浏览器或者nodejs等
浏览器中全局对象就是window对象。可以按下F12输入this验证。在nodejs中全局对象就是global。
函数上下文
说起函数上下文就不得不先说到活动对象
活动对象(activation object)
活动对象在最开始时只包含一个变量, 那就是arguments对象(此对象在全局上下文中是不存在的)。 如果当前上下文时函数上下文,那就将活动对象转变尾变量对象。
活动对象与变量对象的区别
未进入执行阶段之前,变量对象(VO)中的属性都不能访问!但是进入执行阶段之后,变量对象(VO)转变为了活动对象(AO),里面的属性都能被访问了,然后开始进行执行阶段的操作。它们其实都是同一个对象,只是处于执行上下文的不同生命周期。
执行上下文创建阶段中的变量对象
既然执行上下文包括了三个属性,那肯定要确定自己的属性包括了哪些东西吧。本文先看看变量对象属性。
此时并没有执行代码,只是进入了执行上下文。
变量对象包含了:
- 函数的所有形参
- 由参数名及起对应值组成一个变量对象的属性被创建
- 如果没有实参,则值为undefined
- 函数的声明
- 由函数称和对应值(函数对象(function-object))组成一个变量对象的属性被创建
- 如果已经存在相同名称的属性,则完全替换这个属性
- 变量的声明
- 由名称和对应值(undefined)组成一个变量对象的属性被创建
- 如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性。
举个例子
function foo(a) {
var b = 'b',
var c = function () {console.log(c)}
function d() {console.log('d')}
}
foo('a')
创建阶段
此时的VO(变量对象)是:
VO: {
arguments: {
0: 'a',
length: 1
},
b: undefined
c: undefined
d: -> function d() {console.log('d')}
}
执行阶段
代码从上至下顺序执行, VO中的属性逐渐被赋值
此阶段为
VO: {
arguments: {
0: 'a',
length: 1
},
b: 'b'
c: -> function () {console.log('c')}
d: -> function d() {console.log('d')}
}
其实这也从变量对象的角度出发理解了javascript中的函数提升以及变量提升。
console.log(foo) // 会打印函数foo
function foo() {}
var foo = 1
这个例子中因为函数提升以及变量提升的原因其实正确的执行步骤应该如下:
function foo() {} // 函数提升
// var foo = undefined // 变量提升
// 注释掉的原因是因为名称
// 相同,根据变量声明的规则,若变量名与形参名
// 或函数名重复时,并不会干扰或覆盖。
console.log(foo)
foo = 1
在函数执行上下文的创建阶段
VO: {
arguments: {
length: 0
},
foo: -> function foo() {}
}
进入执行阶段后会根据代码依次赋值。这就是js中函数提升, 变量提升产生的原因。
网友评论