javascript中的闭包

什么是闭包?

闭包是指有权访问另一个函数作用域中变量的函数。创建闭包的常见方式是在一个函数内部创建另一个函数。

function createClosureFunction(propertyName) {

    return function (obj1, obj2) {
        var v1 = obj1[propertyName];
        var v2 = obj2[propertyName];

        if (v1 < v2) {
            return -1;
        } else if (v1 > v2) {
            return 1;
        } else {
            return 0;
        }
    }
}

上述v1v2的值通过访问外部函数中的变量propertyName来获取。即使这个内部函数被返回了,而且还是在其他地方被调用了。但它仍然可以访问变量propertyName。之所以还能够访问这个变量,是因为内部函数的作用域链中包含createClosureFunction()的作用域。

当匿名函数从createClosureFunction中被返回后,它的作用域链被初始化为包含createClosureFunction()函数的活动对象和全局变量。

那么如下的这个经典的闭包问题就好解释了。

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

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

这个函数返回一个函数数组。从表面上看,似乎每个函数应该返回自己的索引值,即0的位置返回0,1的位置返回1,以此类推。实际上,每个函数都返回的是10。为什么会出现这样的情况?这是因为每个函数的作用域链中都保存着createFunctions()函数的活动对象,所以他们引用的都是同一个变量i。当createFunctions()函数返回后,变量i的值是10,此时每个函数都引用着保存变量i的同一个变量对象,所以在每个函数内部i的值都是10。

解决这个问题可以使用如下方式,通过匿名函数传递参数的方式来进行修改,因为函数参数是按值传递的,所以会将每次的变量i的值传递给匿名函数的参数num中去。

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

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

另一个需要注意的是闭包中的this对象。

由于匿名函数的执行环境具有全局性,因此this对象通常指向window

var name = 'window'

var obj = {
    name: 'zhangsan',
    sayName: function () {
        return function() {
            return this.name;
        }
    }
}

console.log(obj.sayName()());  //window

解决这个问题,就是将外部作用域中的this对象保存在一个闭包可以访问到的变量中就可以了。

var name = 'window'

var obj = {
    name: 'zhangsan',
    sayName: function () {
        var that = this;
        return function() {
            return that.name;
        }
    }
}

console.log(obj.sayName()());   //zhangsan
如果您觉得本文对您有用,欢迎捐赠或留言~
微信支付
支付宝

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注