执行上下文之变量对象

773 阅读3分钟

前言

对于每个执行上下文,都有三个重要属性:

  • 变量对象(Variable object,VO)
  • 作用域链(Scope chain)
  • this

今天重点讲讲创建变量对象的过程。

变量对象

变量对象(VO)有两种:全局对象和活动对象(AO)

全局对象

顾名思义,全局对象就是全局上下文中的对象,在客户端js中就是window对象。它在顶层代码中可以用this来引用,并访问全局对象中的各个属性和值。

活动对象

活动对象,就是函数上下文中的变量对象。

那么问题来了,你们知道它为什么叫作活动变量吗?

活动对象和变量对象其实是一个东西,只是变量对象是规范上的或者说是引擎实现上的,不可在 JavaScript 环境中访问,只有到当进入一个函数执行上下文中,这个执行上下文的变量对象才会被激活,所以才叫 activation object 呐,而只有被激活的变量对象,也就是活动对象上的各种属性才能被访问。

简单来说,活动对象会在进入函数上下文时被激活,变成活动对象 注意:活动对象是在创建上下文,也就是执行上下文之前的时候被创建,通过函数的arguments属性进行初始化。

包括三个部分:

  1. 函数的形参(全局上下文中除外)
  2. 上下文内部声明的函数(仅限于function声明的) 其实箭头函数不算函数,只能算表达式,所以不算声明函数,而是声明变量
  3. 上下文内部声明的变量(仅限于用var声明的)

从变量对象的角度看代码执行过程

变量对象创建过程

1.将参数对象arguments存放在变量对象中

2.寻找用function声明的函数,然后将函数的内存地址存放到变量对象中

3.寻找用var声明的变量,然后存放到变量对象

注意:重名的函数以后者为准,重名的变量以前者为准

举个例子:

function foo(a) {
  var b = 2;
  function c() {}
  var d = function() {};

  b = 3;

}

foo(1);

在进入执行上下文后,这时候的 AO 是:

AO = {
    arguments: {
        0: 1,
        length: 1
    },
    a: 1,
    b: undefined,
    c: reference to function c(){},
    d: undefined
}

变量对象执行过程

还是上面的例子

AO = {
    arguments: {
        0: 1,
        length: 1
    },
    a: 1,
    b: 2,
    c: reference to function c(){},
    d: undefined
}

思考题

来个例子巩固一下上面所说的:

function test({    
    console.log(a);    
    console.log(foo());    
    var a = 1;    
    function foo({        
        return 2;    
    }}
test();

当运行test函数,对应的上下文创建,可以采用如下形式来表达整个过程

// 创建阶段
testEC={    
    VO:{}, // 变量对象    
    scopeChain:[], // 作用域链    
    this:{}
}
VO={    
    arguments:{...},    
    foo:<foo reference>,    
    a:undefined
}
// 执行阶段
VO -> AO
VO = {    
    arguments: {...},    
    foo: 1,    
    bar: <bar reference>,    
    this: Window
}

本文参考:

JavaScript深入之变量对象

Javascript进阶之变量对象