恶补 JavaScript 基础之变量对象

变量对象(Variable object)

变量对象是与执行上下文关联的数据容器。 这是一个特殊的对象,用于存储在上下文中定义的变量和函数声明。

注意,函数表达式(与函数声明相反)不包含在变量对象中。

变量对象是一个比较抽象的概念。 在不同的上下文类型中,实际上是使用不同的对象呈现的。 例如,在全局上下文中,变量对象是全局对象本身(这就是为什么我们能够通过全局对象的属性名称引用全局变量的原因)。

思考下面这个例子:

  1. var foo = 10;
  2. function bar() {} // 一个函数申明
  3. (function baz() {}); // 一个函数表达式
  4. console.log(
  5. this.foo == foo, // true
  6. window.bar == bar // true
  7. );
  8. console.log(baz); // ReferenceError, "baz" is not defined

此时全局上下文变量对象(VO)将具有以下属性

变量对象 - 图1

作为函数表达式的函数 baz 不包含在变量对象中。 这就是为什么我们尝试在函数本身之外访问它时会出现 ReferenceError 的原因。

注意,与其他语言(例如C / C ++)相比,ECMAScript中 仅仅函数 会创建一个新的作用域。 在函数范围内定义的变量在函数作用域中,在外部不直接可见,也不污染全局变量对象。

使用 eval我们可以进入一个新的(eval的)执行上下文。然而,eval 要么使用全局变量对象,要么使用调用者的变量对象(例如,调用eval 的函数)。

那么函数和它们的可变对象呢?在函数上下文中,变量对象被表示为 活动对象

活动对象(Activation object)

当一个函数时被调用的时候,会创建一个称为 活动对象 的特殊对象。它由形参(formal parameters)和特殊的实参对象(arguments object,它是形参的映射,但带有索引属性)组成。然后 活动对象 被用作函数上下文的一个变量对象

即函数的变量对象可以简单的看做变量对象,但除了变量和函数声明外,它还存储形式参数和实参对象,称为活动对象

  1. function foo(x, y) {
  2. var z = 30;
  3. function bar() {} // 函数申明
  4. (function baz() {}); // 函数表达式
  5. }
  6. foo(10, 20);

foo函数上下文的下一个活动对象(AO)如下

变量对象 - 图2

同样的,函数表达式 baz不包含在变量/活动对象中。

注意,在ES5中,将变量对象和激活对象的概念组合到词法环境模型中,可以在相应的章节中找到详细的描述。

众所周知,在 ECMAScript 中,我们可以使用内部函数,并且在这些内部函数中,我们可以引用父函数的变量或全局上下文的变量。 正如我们将 变量对象 命名为上下文的作用域对象一样,类似于原型链,也有所谓的作用域链。

参考


  1. MDN官方对变量提升的描述
  2. 关于变量提升
  3. 理解 JavaScript 中的执行上下文和执行栈
  4. 了解JavaScript的执行上下文
  5. 维基百科 - 作用域
  6. Facebook 的 ECMAScript 理论专家 Dmitry Soshnikov(最优秀的ECMAScript解读)

恶补JavaScript基础系列


恶补JavaScript基础系列目录地址:https://www.sixtyden.com/archive
恶补JavaScript基础系列是我在从学校毕业入坑前端的学习产物,它主要是我看完书以及其他资料后的一个浓缩总结。以下是我参考的主要资料:

  1. JavaScript高级程序设计
  2. 你不知道的JavaScript(上卷)
  3. 陪你读书(JavaScript web前端)
  4. 王福朋的博客
  5. 冴羽写博客的地方
  6. 汤姆大叔深入 JavaScript 系列
  7. Facebook 的 ECMAScript 理论专家 Dmitry Soshnikov(最优秀的ECMAScript解读)

本人能力有限,如果有错误或者不严谨的地方,请务必给予指出,十分感谢!愿与君共勉。

(完)