1.什么是闭包
要了解闭包,首先得知道啥是闭包,长什么样子
function A() {
function B() {
console.log("我是一个闭包函数");
}
return B
}
var fun = A()
fun()
没错,闭包就长这样!A函数返回的不是B函数的执行结果,而是整个B函数,B函数被拿到A外面执行, 当一个函数保存到了外部,会产生一个闭包。
2.闭包的作用
(1)实现共有变量 防止污染全局变量 例如:累加器
当我们需要一个函数,它会实现一个变量的累加,一般我们会向上面这样定义一个全局变量,执行一次函数时,让全局变量+1。
var count = 0
function add() {
return count++
}
console.log(add());
console.log(add());
console.log(add());
但是这样的话,在庞大的代码量下,我们的全局变量就会泛滥,可读性大大降低。我们应该尽可能将代码封装起来变成一个个函数,而不是一个个变量。这时候闭包就起大作用了。
function add() {
var count = 0
function a() {
++count
console.log(count);
}
return a
}
var res = add()
res()
res()
简单来看,我们要的就是变量是 count,所以在源代码外面又套了一层函数,使原函数变成了闭包函数,将闭包函数传出去调用。
那么问题来了!
闭包函数在外面被调用的时候怎么能访问到count,当add()函数执行完不是被销毁了吗???
其实不会,当add()函数执行到最后一行后,不确定内部函数有没有执行完,所以不会被销毁。
调用闭包函数时,闭包函数处于作用域链的最顶端,之前的add()函数由于没有被销毁,所以它的AO对象还在,count也还在它的AO对象上,所以当闭包函数在自身找不到count变量时,就会沿着作用域链去到下一级也就是add()函数的作用域上去拿到count变量。 (对作用域不熟悉的大大,可以去看看之前写的)# 深入谈谈作用域链
(2)作缓存
function foo() {
for (var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(j);
}, 1000)
}
}
foo()
大大先不妨猜猜它的执行结果!! 它的执行结果是同时输出一个10! 那么疑惑又来啦,为啥不是从0~9 每秒输出一个数呢? 因为,定时器每秒执行一次,而一个for循环执行速度是非常快的,时间可以忽略不计,当定时器还没等到一秒,for循环早已经执行完了,不会等定时器,for循环执行完就同时创建了10个计时器,而此时变量i也变成了10,所以一秒过后就同时输出了10个10。 那有没有什么解决办法呢? 下面看看闭包表现!!
function foo() {
for (var i = 0; i < 10; i++) {
function fun(j) {
setTimeout(function() {
console.log(j);
}, 1000 * j)
}
fun(i)
}
}
foo()
将定时器用函数fun包起来,此时每一次for循环就会执行fun()函数,将i传进去就变成了fun()函数的变量,此时定时器就成了fun()函数的闭包函数,不确定闭包函数有没有执行完时fun()函数就不会被销毁,所以i一直存在变量j中,而j又一直存在fun()函数的AO对象上,等着定时器执行时从作用域链上去找!
因为fun()函数被创建时又立马被调用,所以将函数变成质子形函数优化下!
function foo() {
for (var i = 0; i < 10; i++) {
(function(j) {
setTimeout(function() {
console.log(j);
}, 1000 * j)
})(i)
}
}
foo()