闭包

一、《JavaScript高级程序设计》这样描述:

闭包是指有权访问另一个函数作用域中的变量的函数;

《JavaScript权威指南》这样描述:

从技术的角度讲,所有的JavaScript函数都是闭包:它们都是对象,它们都关联到作用域链。

《你不知道的JavaScript》这样描述:

当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行。

二、闭包的经典栗子
另一个很经典的例子就是for循环中使用定时器延迟打印的问题:

for (var i = 1; i <= 10; i++) {
    setTimeout(function () {
        console.log(i);
    }, 1000);
}

在这段代码中,我们对其的预期是输出1~10,但却输出10次11。这是因为setTimeout中的匿名函数执行的时候,for循环都已经结束了,for循环结束的条件是i大于10,所以当然是输出10次11咯。
究其原因:i是声明在全局作用中的,定时器中的匿名函数也是执行在全局作用域中,那当然是每次都输出11了。

原因知道了,解决起来就简单了,我们可以让i在每次迭代的时候,都产生一个私有的作用域,在这个私有的作用域中保存当前i的值。

for (var i = 1; i <= 10; i++) {
    (function () {
        var j = i;
        setTimeout(function () {
            console.log(j);
        }, 1000);
    })();
}

这样就达到我们的预期了呀,让我们用一种比较优雅的写法改造一些,将每次迭代的i作为实参传递给自执行函数,自执行函数中用变量去接收:

for (var i = 1; i <= 10; i++) {
    (function (j) {
        setTimeout(function () {
            console.log(j);
        }, 1000);
    })(i);
}

三、闭包的应用
闭包的应用比较典型是定义模块,我们将操作函数暴露给外部,而细节隐藏在模块内部:

function module() {
    var arr = [];
    function add(val) {
        if (typeof val == 'number') {
            arr.push(val);
        }
    }
    function get(index) {
        if (index < arr.length) {
            return arr[index]
        } else {
            return null;
        }
    }
    return {
        add: add,
        get: get
    }
}
var mod1 = module();
mod1.add(1);
mod1.add(2);
mod1.add('xxx');
console.log(mod1.get(2));

你可能感兴趣的:(闭包)