JS学习笔记——闭包

1. 什么是闭包

简单的说,闭包是指一个函数这个函数的执行环境。下面是一个最简单的闭包。函数test()根据作用域链的规则访问到了函数外面的value变量。

var value = "pxz";
function test() {
    console.log(value);
}

上述例子跟我们常见的闭包不太一样,常见的闭包形式是函数嵌套函数并且返回函数。我们再看上面那个例子,变量value赋给了全局对象,我们希望避免全局变量污染,就要把这个闭包放进函数中。如果是一次性的函数,就写成立即执行函数;如果需要调用,就写成返回函数形式。

一般创建闭包的方式,是在一个函数中创建另一个函数,并将该函数作为返回值返回。一般情况下,一个函数返回了,那么这个函数的活动对象(变量对象)就会被销毁,这个变量对象就不在当前作用域链上了,但是闭包跟一般情况不同。

2.闭包用途

闭包可用来实现私有变量,具体可参考JS学习笔记——私有变量。

3.一个闭包常见的错误

1.经典闭包例子中,test函数的返回值是一个匿名函数组ary,咋一看,匿名函数组里的每一个函数返回各自的索引值。但其实并不是这样的。匿名函数组里的每一个函数返回的值一样且都为n。我们调用了test函数,返回还是函数,赋给fun。在fun里可以访问到fun外test函数中的变量,比如var i,即使此时已经从test函数中返回。我们可以形象地把这个过程理解为返回函数ary闭包了外层函数的变量i。由于变量i在外层函数只有一份拷贝,所以函数组ary返回的i都是一个i,test函数执行完毕后,i变成了n。

要使得返回的函数组里的每个函数都不一样,我们需要为每个返回函数拷贝一份变量i。在2.立即执行函数中,没有直接使用外层函数变量i,而是将i作为函数参数传入,这样就能在函数内部拷贝一份变量了。

3.返回函数中,我们在2.立即执行函数的基础上外包一层函数,使得满足闭包要求,返回函数。

//1.经典闭包例子
function test(n) {
    ary = [];
    for(var i = 0; i < n; i++) {
        ary[i] = function() {return i;};
    }
    return ary;
}
var fun = test(5)[4];
console.log(fun());//5

//2.立即执行函数-拷贝变量
//每一份i都有拷贝,但这不是闭包,返回值不是函数
function test(n) {
    ary = [];
    for(var i = 0; i < n; i++) {
        ary[i] = (function(x) {return x;})(i);
    }
    return ary;
}
console.log(test(5)[4]);//4

//3.返回函数
//在2的基础上,在外面套一层函数
function test(n) {
    ary = [];
    for(var i = 0; i < n; i++) {
        ary[i] = (function(x) {
        	return function() {
        		return x;
        	}
        })(i);
    }
    return ary;
}
console.log(test(5)[4]());//4

【Reference】

  1. 《javascript高级程序设计》(第3版)
  2. 大部分人都会做错的经典JS闭包面试题 http://www.cnblogs.com/xxcanghai/p/4991870.html
  3. 「每日一题」JS 中的闭包是什么? https://zhuanlan.zhihu.com/p/22486908
posted @ 2017-05-24 16:09  水煮海鲜  阅读(135)  评论(0编辑  收藏  举报