wangzhenggui/blog

javaScript深入之变量对象

Opened this issue · 0 comments

前篇

在上个章节中我们讲到了javaScript的执行上下文,对于每一个上下文而言,都有3个重要的属性!

  • 变量对象
  • 作用域链
  • this

变量对象

变量对象是与执行上下文相关的数据作用域,存储了在上下文中定义的变量和函数声明。
因为不同执行上下文下的变量对象稍有不同,所以我们来聊聊全局上下文下的变量对象和函数上下文下的变量对象。

全局上下文

  1. 全局上下文中的全局对象就是window对象,当然在node环境下就另说了哈!
    console.log(this); // window
  2. 全局对象是有Object这个构造函数实例化的一个对象
    console.log(this instanceof Object); // true
  3. 预定义了一大推函数和属性「可以直接在控制台里面使用的API函数或者对象」
    Math对象 parseInt() 方法等
  4. 作为全局变量的宿主对象「全局对象会自动绑定到window对象下」
    var a = 123;
    console.log(this.a); // 123
    

函数上下文

再说函数上下文的时候,先介绍一个名词--活动对象。在函数上下文中我们用活动对象表示变量对象。
当进入一个执行上下文中,这个执行上下文的变量对象才会被激活,只有被激活之后,变量对象上的各种属性才能被访问
活动对象是在进入函数上下文时刻被创建的,它通过函数的 arguments 属性初始化。

进入执行上下文

当进入执行上下文的时,还没有执行代码块

  1. 函数的所有形参
    由形参的参数名称和对应值组成一个变量对象的key-value,如果实参没有,则value为undefined
function demo(a) {
       }
    demo(1);
    AO = {
      a:1;    // 如果没有实参,这里就是undefined
    }
  1. 函数声明
    由函数名称和对应值(函数对象(function-object))组成一个变量对象的key-value,如果存在一个
    相同的变量名称,则会完全取代这个变量

  2. 变量声明
    由名称和对应值(undefined)组成一个变量对象的key-value被创建,这个value此时都是undefined(变量提升),如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性

案例说明:

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

在执行上下文初始化的时候,只会有一个变量对象

AO = {
    arguments: {
        length: 1 // 形参个数
    }
}

在进入上下文环境的时候,会给变量对象添加形参、函数声明、变量声明等初始属性

AO = {
    arguments: {
        length: 1 // 形参个数
    },
   a: 1,
   b: undefined,
   c: reference to function c(){},
   d: undefined,
}

下面我们开始说代码执行的时候又有什么不同?

代码执行

在代码执行阶段,会顺序执行代码,根据代码,修改变量对象的值

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

总结

  1. 全局上下文的变量对象初始化是全局对象
  2. 函数上下文的变量对象初始化只包括 Arguments 对象
  3. 在进入执行上下文时会给变量对象添加形参、函数声明、变量声明等初始的属性值
  4. 在代码执行阶段,会再次修改变量对象的属性值

思考题

function demo() {
  console.log(c);
  var c =123;
  function c() {
    console.log('function')
  }
}
demo();
function demo(c) {
  console.log(c);
  var c =123;
  function c() {
    console.log('function')
  }
}
demo(1);

上面俩个例子换了一下打印c的位置,俩个运行的结果是否和你预想的一致?
我们来看一下第一段代码,进入demo的执行上下文时,

AO = {
    arguments: {
        length:0,
    },
    c:  reference to function c(){}, 
}

可能有人会说了,这里的c为什么不是undefined的呢,因为在进入执行上下文时,会先函数声明,在变量声明,又有人会问了,就算变量后声明,为什么不会覆盖掉之前的值和类型呢?在上面的执行上下文小结中有写到 变量名称跟已经声明的形参或函数相同,则变量声明不会干扰已经存在的这类属性

再来看下第二个例子,第二个例子的运行结果和你想的还有出入吗?
第二个例子比第一个例子多了一个形参,我们通过上面的进入执行上下文分析,可以知道首先会声明形参,那么c: 1,为什么输出的结果还是function(){}呢?我们在来看看上面在执行上下文分析中的一段话,在声明函数的时候,如果存在一个相同的变量名称,则会完全取代这个变量
现在知道为什么输出的是function(){} 这个结果了吧!!!