JavaScript闭包理解的关键 - 做用域链

阮一峰的一篇文章已经对闭包的用途、概念讲解地相对清晰了。javascript

闭包就是可以读取其余函数内部变量的函数。html

 

但我认为里面对于做用域链的解释还不够清晰,这里做一些补充。java

闭包之因此能够读取外部函数的内部变量,即便外部函数已经返回,是由于它把外部函数的活动对象加到了本身的做用域链中。闭包

而理解做用域对于彻底理解闭包很重要。函数

 

做用域链是什么?

对于这段代码测试

    function compare(value1,value2){
        alert("this "+this+" arguments "+arguments);
        if(value1 < value2){
            return -1;
        }else if( value1 > value2){
            return 1;
        }else{
            return 0;
        }
    }

    var result = compare(5,10);

JavaScript高级程序设计里这样写this

在建立函数compare()时,会建立一个预先包含全局变量的做用域链,当调用时,会为函数建立一个执行环境。spa

其做用域链中包含两个变量对象:本地活动对象和全局变量对象。设计

做用域链本质上是一个指向变量对象的指针列表。3d

画出来大概是这个样子的

 

举个闭包的例子

    var name = "the window";

    var object = {
        name: "My Object",
        getNameFunc: function(){
            return function () {
                return this.name;
            }
        }
    }

不少人不明白为何this.name不指向包含函数中的object.name。

对于这个问题,一样是这本书中有一句话

每一个函数被调用时都会自动取得两个特殊变量:this 和 arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止。

 

意思是,匿名函数的this是按做用域链搜索的,当在匿名函数自己的活动对象中就找到this后,就不会再向外搜索了。this指向的活动对象中并无name属性,因此指向了全局的this。

 

做用域链画出来是这样的

 

如今明白了吧,闭包之因此有这样的表现,是由于搜索标识符时按照做用域链,从内向外搜索。

再看下这个例子你会更清楚。

 

    var name = "the window";

    var object = {
        name: "My Object",
        getNameFunc: function(){
            var that = this;
            return function () {
                alert("that "+that);
                return that.name;
            }
        }

    }

 

变化在于这里

 

匿名函数在自身的活动对象里没找到that对象,就沿做用域链向上找,在getNameFunc()的活动对象里找到了that,指向的就是this。

因此你能够按F12本身测试一下,输出结果是"My Object"

相关文章
相关标签/搜索