前面的文章曾经说到过闭包的问题,参见《闭包导致的问题》,今天回头看看,并没有介绍到闭包,仅仅提到了闭包的概念而已。
首先我们得理解在javascript中,什么是闭包?
谈到闭包,就必然要涉及变量,在javascript中,变量一般分为全局变量和局部变量。从我的角度(初学者角度)来理解的话,其实闭包的主要作用在于封装变量为局部变量,减少到全局作用域的污染。
那么,究竟什么是闭包呢?
function outer (){ // 定义一些变量 function inner(){ // 内部函数执行代码块 } }
从上面的代码来理解闭包的定义,如果要产生闭包的效果,就必须能够在outer外部调用到inner,放在后面再说,这里仅仅理解闭包的概念。
outer函数定义了一个作用域,在这个作用域内声明了函数inner,函数inner能够影响到的范围,或者说可以调用到的变量所在的区域(当然也能引用到全局作用域变量),就是inner闭包。
用一张图片来描述的话,红色边框表示该函数的作用域范围,而里面的半透明填充色即为外部函数的内部声明函数的闭包范围,其实闭包就相当于父函数的作用域。
当我们将inner函数传递到outer函数外部调用的时候,就产生了闭包,这个闭包其实就是outer函数的作用域,这样,就能够全部定义局部变量,从而减少全局变量的定义。
再举一个闭包常见的例子:循环遇到定时器,或者事件处理函数,这里举定时器的例子。
function foo() {
for (var i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
}
foo();
打开控制台可以看到,会打印三个3出来,而不是我们所期望的相隔1秒,分别打印0,1,2。
这里其实就是当执行到延迟定时器内部函数块console.log(i)时,循环已经结束,此时i=3,而不是延迟定时器在执行时,分别创建作用域,所以这里必然结合闭包,给每次循环单独创建一个作用域,
function foo() {
for (var i = 0; i < 3; i++) {
(function (i) {
setTimeout(function () {
console.log(i)
}, 1000);
})(i);
}
}
foo();
如此,就能实现相隔1秒分别打印0,1,2。
只要理解了闭包的概念,再去看各种涉及到闭包的例子,应该比较容易理解javascript中的痛点--闭包--了。