美文网首页程序员让前端飞
深入理解闭包(二)——变量对象

深入理解闭包(二)——变量对象

作者: 薛普定朗谔克 | 来源:发表于2017-05-09 15:03 被阅读0次

原文地址:深入理解闭包(二)——变量对象

执行一个函数之前,JavaScript引擎会进行准备工作,这个准备工作指的就是执行上下文,也叫执行上下文环境,也叫执行环境。
下面是一个执行上下文的周期图,其中变量对象(Variable Object)是重点之一,只有理解了它,我们才能知道一段代码的执行过程中先做什么,后做什么,我们今天就探讨一下变量对象在执行上下文生命周期中都经历了怎样的变化:

创建阶段

  1. 建立arguments对象(参数对象,当某个函数接收参数的时候,会将参数封装成arguments对象)。
  2. 检查当前上下文的函数声明,也就是使用function声明的函数。在变量对象中以函数名建立一个属性,属性值为指向该函数所在的内存地址的引用。如果函数名的属性已存在,那么该属性将会被新的引用所覆盖。
  3. 检查当前上下文的变量声明,也就是使用var声明的变量,对于每一个变量声明,变量对象会以变量名建立一个属性,属性值为undefined。函数的声明比变量优先级要高,并且定义过程不会被变量覆盖,除非是赋值。

执行阶段

执行阶段没有什么难以理解的,有两点需要知道一下:

  1. 代码执行时按照顺序,该赋值时赋值,该调用时调用,这个一看后面的栗子就明白了。
  2. 变量对象转变为了活动对象(Active Object),其实这俩是一个东西,只是所处的时期不同罢了。

栗子们

栗子1:

console.log(a);  //a is not defined

上面代码执行环境中根本没有定义变量a

console.log(a);  //undefined
var a = 10;

虽然同样没有打印a的值,但是跟之前不同的是,这里执行环境中查找到了变量a,但是在打印时它还没有进行赋值,因为查找变量a是在执行上下文创建阶段完成的,并定义为undefined,然后才进入执行阶段,但是打印a的语句在前面,赋值语句在后面,所以打印出来的是a的初始值undefined,这也就体现了前面说的执行阶段是按照顺序执行相关赋值、打印、函数调用等代码。我们可以把上面代码等效成下面的形式:

var a;
console.log(a);
a = 10;

栗子2:

console.log(test);     //function test(){ return 1;}
console.log(test());   //1   test是函数,test()是函数调用之后返回的值
function test() {
    return 1;
}

上面代码在创建阶段检查到的是函数声明,因此可以顺利打印函数。

console.log(test);      //undefined
console.log(test());    //test is not a function
var test = function () {
    return 1;
}

这段代码也是要打印函数,但是却得到了截然不同的效果,因为这里的test其实是一个变量声明,只不过给它赋值的是一个函数,但是在创建阶段它的初始值仍是undefined。

栗子3:

function test(x,y) {
    console.log(arguments);   //{ '0': 1, '1': 2 }
    console.log(a);           //undefined
    console.log(b);           //function func(){  return 2;  }
    console.log(b());         //2
    console.log(c);           //unundefined
    var a = 10;
    console.log(a);           //10
    function b() {
        return 1;
    }
    function b() {
        return 2;
    }
    var b;
    var c=function () {
        return 3;
    }
    console.log(c);          //function func(){  return 2;  }
    console.log(c());        //3
}
test(1,2);  
  • 检查到函数调用时传入了参数(1,2),以参数为属性值封装成arguments对象{ '0': 1, '1': 2 }。
  • 检查函数声明,先检查到第一个b函数,便以b为属性名,b函数的内存地址引用为属性值建立一个属性。但紧接着又检查到一个b函数,属性值将会被后面的b函数覆盖,因此打印b函数时得到的是后面声明的b函数。
  • 检查变量声明,得到变量a,b,c,由于函数b的存在,b属性已经被创建了,并且这里的变量b并没有赋值,因此它不会覆盖属性b的值,而是跳过。不过另外的变量a和c都顺利创建属性a和c,属性值为undefined。
  • 按顺序执行代码,第一次打印a时还没有经过赋值,因此输出undefined,第二次打印a时已经赋值,因此输出10,其他同理,不再解释。

如果按照执行顺序把栗子3代码做个等效的话,是下面这样的:

function test(x,y) {
    function b() {
        return 2;
    }
    var a;
    var c;
    console.log(arguments);   
    console.log(a);           
    console.log(b);          
    console.log(b());         
    console.log(c);          
    a = 10;
    console.log(a);          
    c=function () {
        return 3;
    }
    console.log(c);          
    console.log(c());        
}
test(1,2);  

结语

现在我猜你对于一段代码的执行过程应该已经了解得差不多了,你不要觉得这跟闭包看起来没有关系就忽略这里的知识点,其实你对基础的东西理解透彻,对后面难点的理解是潜移默化的,不仅仅是闭包,很多难点在夯实的基础面前都是赤身裸体的,很容易就能看得一清二楚。今天关于变量对象就说到这里,下一次我们会进一步探查执行上下文的奥秘。

相关文章

  • 深入理解闭包(二)——变量对象

    原文地址:深入理解闭包(二)——变量对象 执行一个函数之前,JavaScript引擎会进行准备工作,这个准备工作指...

  • 2018-07-11

    深入理解闭包: 一、变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域。 变量的作用域无非...

  • 深入理解javascript原型和闭包(完结)

    深入理解javascript原型和闭包(1)——一切都是对象 深入理解javascript原型和闭包(2)——函数...

  • 理解闭包

    欢迎移步我的博客阅读:《理解闭包》 闭包 是指可以包含自由(未绑定到特定对象)变量的代码块;这些变量不是在这个代码...

  • JS闭包理解

    闭包的概念 闭包就是能够读取其他函数内部变量的函数。 一、变量的作用域 要理解闭包,首先必须理解Javascrip...

  • 深入理解javascript原型和闭包[目录]

    文章地址:深入理解javascript原型和闭包 文章:深入理解javascript原型和闭包 目录列表 (不能跳...

  • 闭包、定时器

    一、什么是闭包? 有什么作用 1.变量的作用域  要理解闭包,首先必须理解JavaScript的变量作用域。变量的...

  • 闭包(Closure)

    我对闭包的理解 个人理解 : 闭包就是能够读取其他函数内部变量的函数。使用闭包主要是设计私有的方法和变量 优点:可...

  • JS-闭包

    0.闭包 理解闭包的关键在于:外部函数调用之后其变量对象本应该被销毁,但闭包的存在使得我们仍旧可以访问外部函数的变...

  • 深入理解闭包(三)——确定this指向

    原文地址:深入理解闭包(三)——确定this指向 我们在前面说过,在执行上下文创建过程中做了三件事:创建变量对象,...

网友评论

    本文标题:深入理解闭包(二)——变量对象

    本文链接:https://www.haomeiwen.com/subject/vyzbtxtx.html