变量对象

什么是变量对象(Variable object,VO)?

变量对象是执行上下文中的数据作用域,它存储了当前上下文的变量和函数声明。
执行上下文一般分三种 1.全局执行上下文。 2.函数执行上下文
3.evel(一般不推荐使用)

全局上下文的变量对象

当程序运行的时候,全局上下文会预先定义一个全局对象,包含了一些常用的方法,如:Math,document...
由这些组成的全局对象就是全局上下文的变量对象

函数执行上下文的变量对象

而函数的上下文变量对象和全局的不同它分为两个阶段创建阶段和执行阶段,它的创建过程主要由三部分组成 1.建立 Argument 对象,检查当前上下文的形参建立相应的属性。 2.检查函数声明.创建指向函数的引用 3.检查变量声明,由 var 关键字声明的变量(let 和 const 不会加入到变量对象创建阶段会进入暂时性死区),通过变量提升会初始化为 undefined 如果遇到同名函数声明会跳过。
举个栗子:

function a() {
  console.log(b); //function b
  function b() {
    console.log('Hello');
  }
  var b = 'Hi';
  var c = 'Hi2';
  console.log(b); //'Hi'
}

上面的栗子在创建阶段函数和变量提升,因此打印出函数 b,有人会疑惑为什么不是 undefined 后面的覆盖前面的啊,因为在上面第三点中提到了 如果 var 声明的变量遇到同名的会跳过,后面的 b 输出 hi 因为是在执行阶段赋值产生了覆盖行为。
创建过程如下

//创建阶段
VO:{
        argument:{
            length:0,
        }
        b:< reference> function b(){},
        c:undefined
    }

//执行阶段
AO:{
        argument:{
            length:0,
        }
        b:Hi,
        c:Hi2
    }

这里不禁再次疑问 AO 是什么,其实 AO 就是 VO 两个是指的一个对象,只是在不同阶段发生了变化,当可执行函数在执行栈的最顶端时,也就是当前函数执行上下文被执行,VO 就变成了 AO,并进行一系列的赋值操作
在来看一个

function a(b) {
  console.log(b); //function b{}
  function b() {
    console.log('Hello');
  }
  var b = 'Hi';
  var c = 'Hi2';
  console.log(b);
}
a(1);

这个明明有传参数为什么还是最后输出来的还是 function b 呢,这里又有一个知识点当传入的形参和函数声明同名时,函数声明会覆盖形参
总结一下: 1.全局上下文的变量对象就是 window 2.函数上下文变量对象由形参,函数声明,变量声明组成 3.函数上下文变量对象分为创建阶段和声明阶段,两个阶段都会对属性进行更改 1.创建阶段:如果 function 关键字声明的变量与形参同名将会覆盖原有属性,var 声明的变量如果与
function 声明的重名了将不会影响到已经声明的函数,会跳过,其他通过 var 声明的会初始化为
undefined 2. 执行阶段:这个阶段会再次对变量进行修改,进行相应的赋值,对任何已经有的值都会进行覆盖。列
如函数声明