javascript

JavaScript中闭包与this对象

2019-06-30  本文已影响38人  若隐爱读书

闭包

闭包与匿名函数容易混淆。闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数

function createComparisonFunction(propertyName){
    return function ( object1,object2){
        var value1 = object1[propertyName];
        var value2 = object2[propertyName];
        if(value1 < value2){
            return -1;
        }else if (value1 > value2){
            return 1;
        }else{
            return 0;
        }
    };
}

在上面的例子中,3、4行定义value1 value2的过程中,调用了外部函数中的变量propertyName。即使这个内部函数返回了,而且在其他地方调用了,但仍可以访问变量propertyName。之所以能够访问这个变量,是因为内部函数的作用域链中包含createComparisonFunction()的作用域。要搞清楚其中的内容,就要从理解函数被调用的时候发生了什么入手。
当某个函数被调用时,会创建一个执行环境,以及相应的作用域链。然后,使用arguments和其他命名参数的值来初始化函数的活动对象。但在作用域链中,外部函数的活动对象始终处于第二位,外部函数的外部函数的活动对象处于第三级。

变量

作用域链的这种配置机制引出了一个值得注意的副作用,即闭包只能取得包含函数中任何变量的最后一个值。下面的例子可以清晰的说明这个问题。

function createFunctions(){
    var result = new Array();

    for(var i=0; i<10;i++){
        result[i] = function(){
            return i;
        };
    }
}

这个函数会返回一个函数数组,表面上看似乎会返回[0,1,...]。但实际上却是返回了[10,10,...],因为每个函数的作用域链中都保存着createFunctions()函数的活动对象,所以它们引用的都是同一变量i,所以它们引用的都是同一个变量i,所以最后返回都是10.但是,我们可以通过创建另外一个匿名函数强制让闭包的行为符合预期

function createFunctions(){
    var result = new Array();
    
    for(var i=0; i<10;i++){
        result[i] = function(num){
            return function(){
                return num;
            };
        }(i);
    }
    return result;
}

在上面的例子中,我们没有直接把闭包赋值给数组,而是定义了一个匿名函数,并将立即执行该匿名函数的结果赋值给了数组。这里的匿名函数有一个参数num,也就是最终要返回的值。在调用每个匿名函数时,我们传入变量i。由于函数传参时传值的,因此i的值就会复制给num。而在这个匿名函数内部,又创建了一个访问num的闭包。这样一来,数组中每个值就可以获取num的一个副本,因此就会有不同的返回值了。

this对象

在闭包中使用this对象也可能导致一些问题。this对象是在运行时绑定的,匿名函数的执行环境具有全局性,因此其this往往指向window。但有时候由于闭包编写方式不同,这一点可能也不明显。

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

object.getNameFunc()返回了一个匿名函数,然后调用执行这个匿名函数。因为这个匿名函数不是作为某个对象的方法来调用执行,所以它的this就是wlndow对象.

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

在定义匿名函数之前,我们把this对象赋值给一个that。定义闭包之后,闭包也可以访问这个变量。因此,就可以获得object的变量name。

上一篇下一篇

猜你喜欢

热点阅读