JS闭包简单梳理

闭包原理

闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。 —— from: 百度百科

基本概念

  1. 变量作用域:在函数中声明的变量拥有函数作用域,只有在该函数内部才能访问到这个变量。
  2. 变量生命周期:对于在函数中声明的变量来说,当退出函数时,随着函数调用的结束而被销毁。

简述自己的理解:在函数调用结束后还能访问函数内部变量,在这里就产生了一个闭包。

典型实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 <!--在一个函数内部创建另一个函数-->

const a = () => {
let b = 0;
return () => {
b += 1
console.log(b);
}
}

const c = a();

c() //1
c() //2

从示例中,我们可以看到,在a函数执行完后,我们还可以通过a函数返回的匿名函数,修改a函数内部的b变量,这样就形成了一个闭包。

经典问题

1
2
3
4
5
6
for(var i=0; i<10; i++) {
setTimeout(()=>{
console.log(i)
})
}
//10,10,10...

一个简单的for循环,每次循环时,变量i的值都会增加,我们期望在console.log时,输出每次循环的i值。但setTimeout中,函数内部引用的i在取值时, 由于是异步执行,循环已经执行完成了,只能取到i的最终值。因此,当setTimeout中的函数执行时,得到的i是最终值10。

利用闭包的思路解决问题

1
2
3
4
5
6
7
8
for(var i=0; i<10; i++) {
(index=> {
setTimeout(()=>{
console.log(index)
})
})(i)
}
//0,1,2...

通过上面闭包的典型实践,我们在每次循环时执行一个匿名函数,函数接收i为参数,保持在函数内部,在setTimeout执行回调时,访问的是匿名函数内部的i值。以此实现访问每次循环时不同的i值。