jejuin / Blog

我的博客:记录、总结、分享前端知识
MIT License
4 stars 0 forks source link

JavaScript 之变量对象 #10

Open jejuin opened 4 years ago

jejuin commented 4 years ago

变量对象

Image  11

一段代码在开始执行时,首先会创建一个执行上下文。而当进入执行上下文时,就会创建一个变量对象,此时代码还未执行。

每个执行上下文都有一个变量对象。

变量对象是与执行上下文相关的数据作用域,执行上下文中定义的所有变量和函数都保存在这个对象中。可以将变量对象理解为作用域这个抽象概念的实体,当代码执行时,是从变量对象中查找是否存在相应的变量的。它具体是如何查找的呢?我们继续往下看。

变量对象的创建,依次经历了以下三个过程:

变量对象的创建,是优先扫描函数声明的,如果变量与函数同名,则以函数为主。下面简单解释下原因: 假设变量对象(作用域)中已经存在一个名为 foo 的属性,它代表一个函数引用。当扫描变量声明时,又遇到一个命名为 foo 的变量,解释器会询问变量对象(作用域)是否已经存在一个该名称的标识符,如果存在,解释器会忽略该指令,继续执行;否则它会要求变量对象声明一个命名为 foo 的属性,并赋值为 undefined。

Image  12

由于全局执行上下文和函数执行上下文中的变量对象有一些差异,所以下面对它们分别进行介绍。

全局执行上下文

在全局执行上下文中,变量对象初始化是全局对象,也就是 window 对象。因此所有声明的全局变量和函数都是作为 window 对象的属性和方法创建的。

什么是全局对象

全局对象是预定义的对象,作为 JavaScript 的全局函数和全局属性的占位符。通过使用全局对象,可以访问其他所有预定义的对象、函数和属性。

全局对象不是任何对象的属性,所以它没有名称。

在顶层 JavaScript 代码中,可以用关键字 this 引用全局对象。

因为全局对象是作用域链的头,这意味着在顶层 JavaScript 代码中声明的所有变量都将成为全局对象的属性。

函数执行上下文

在函数执行上下文中,变量对象就是其活动对象(activation object, AO)

什么是活动对象?

变量对象和活动对象其实是一个对象,两者意思相同,只是处于执行上下文的不同生命周期。

执行上下文的生命周期包括两个阶段:创建阶段和执行阶段。

变量对象就是在创建阶段时初始化的,此时代码还未执行,变量对象中的属性不能被访问。进入执行阶段后,开始逐行执行代码,此时变量对象就会被激活变成活动对象(AO),其各种属性才能被访问。此时就可以通过查找变量对象上是否存在某属性的方式查找声明的变量和函数,获取到引用后进行变量赋值、函数调用等操作。


我们一起来看下下面这段代码生成的变量对象是什么样子的:

function fn(a, b) {
    var c = 2;
    function fn1() {}
    var d = function () {};
}

fn(1, 2, 3);
// fn 执行上下文中的变量对象
VO = {
    Arguments: {
        0: 1,
        1: 2,
        2: 3,
        length: 3
    },
    a: 1,
    b: 2,
    c: undefined,
    fn1: <fn1 reference>,
    d: undefined
}

Image  13

此时的变量对象是在代码执行前创建的,变量对象中的属性都不能访问。在进入执行阶段之后,变量对象变成了活动对象,此时变量对象的属性可以被访问了。然后开始执行代码,代码执行的过程中可能会修改变量对象的属性值。

还是上面的例子,当代码执行完毕,这时的 AO 变成:

AO = {
    Arguments: {
        0: 1,
        1: 2,
        2: 3,
        length: 3
    },
    a: 1,
    b: 2,
    c: 2,
    fn1: <fn1 reference>,
    d: <FunctionExpression "d" reference>
}

总结:

参考:

JavaScript深入之变量对象 JavaScript 之深入理解执行上下文