JavaScript变量对象

JavaScript中,当调用一个函数时,就会有相应的一个执行环境被创建。而一个执行环境的生命周期包含两个时期

执行环境生命周期:

  • 创建阶段
    • 这个阶段,执行环境会创建变量对象,建立作用域链及确定this的指向
  • 代码执行阶段
    • 开始执行代码时,会完成变量赋值,函数调用,以及其他代码的执行

变量对象(Variable Object)

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

  1. 建立arguments对象。检查当前上下文中的参数,建立该对象下的属性与属性值。

  2. 检查当前上下文的函数声明,也就是使用function关键字声明的函数。在变量对象中以函数名建立一个属性,属性值为指向该函数所在内存地址的引用。如果函数名的属性已经存在,那么该属性将会被新的引用所覆盖。
  3. 检查当前上下文中的变量声明,每找到一个变量声明,就在变量对象中以变量名建立一个属性,属性值为undefined。如果该变量名的属性已经存在,为了防止同名的函数被修改为undefined,则会直接跳过,原属性值不会被修改。

根据这个规则,理解变量提升就变得十分简单了。在上面的规则中我们看出,function声明会比var声明优先级更高一点。举个例子:

function demo(){
  console.log(a); //undefind   testfn(); //11   var a = 2;   function testfn() {     console.log(11);   } }
demo();

创建过程(EC:execution context)

demoEC = {

  VO: {},// 变量对象 

   scopeChain: {},

   this: {}

}

VO 为 Variable Object的缩写,即变量对象VO

VO= {

  arguments: {...}, //注:在浏览器的展示中,函数的参数可能并不是放在arguments对象中,这里为了方便理解

  testfn: <foo reference>, // 表示foo的地址引用

  a: undefined
}

未进入执行阶段之前,变量对象中的属性都不能访问!但是进入执行阶段之后,变量对象转变为了活动对象,里面的属性都能被访问了,然后开始进行执行阶段的操作。(PS:这里可以看出其实变量对象活动对象其实是指向同一个,只是处在执行环境不同生命周期)

当走到demo();时,进入执行阶段

执行阶段VO -> AO // Active ObjectAO
AO = {
  arguments: {...},
  foo: <foo reference>,
  a: 1

}

因此,上面的例子demo,执行顺序就变成了这样

function demo() {
  function testfn() {
    console.log(1);
  }
  var a;
  console.log(a);  
  a = 1;
}

demo() ;

function demo2() {
  console.log(box);
  console.log(car);
  var car = "BWM";
  console.log(car);
  var box = function () {
    console.log("box");
  } 
  function car() {

    console.log("carfn");
  }

}
demo2();

创建阶段VO

VO = {

  arguments:{...},

  car:<car refrence>, //这里car不会被后来var car变量所覆盖,而是直接跳过

  box:undefind

}

当代码走到demo2();时,VO>AO

AO = {

  argument:{...},

  car:"BWM",

  box:<boxrefrence>

}

因此,demo2的执行顺序就变成了这样

function demo2() {
  function car() {
    console.log("carfn");
  }
  var box;  

  console.log(box); //undefind

  console.log(car); //<car refrence>  

  car = "BWM";

  console.log(car); //"BWM"
  box = function() {

    console.log("box");
  }
}

demo() ;

全局上下文的变量对象

以浏览器中为例,全局对象为window。
全局上下文有一个特殊的地方,它的变量对象,就是window对象。而这个特殊,在this指向上也同样适用,this也是指向window。

windowEC = {

  VO:window,

  Scope chain:{},

  this: window

}

除此之外,全局上下文的生命周期,与程序的生命周期一致,只要程序运行不结束,比如关掉浏览器窗口,全局上下文就会一直存在。其他所有的上下文环境,都能直接访问全局上下文的属性。

参考链接:http://mp.weixin.qq.com/s/a_oWYwK0eI_74bMVoGLwCA

 

 

 

 

 

posted @ 2017-03-03 23:23  xplblog  阅读(218)  评论(0编辑  收藏  举报