这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战
经常听到闭包,那什么是闭包呢?网上各种答案,但就是没有对于闭包的定义;我个人的对闭包的理解就是:一个函数包着另一个函数,形成自己的作用域链,并能让外部调用函数里面的变量。想了解闭包就得知道什么是局部变量、全局变量、作用域、作用域链。话不多说,直接上代码:
var a = 1;
var b = 23;
function fn() {
var b = 2;
return function bar() {
return a + b;
}
}
var f = fn();
console.log(f())
代码中分别声明了三个变量以及函数fn、函数bar;每一个函数都有自己的作用域,函数fn、和函数bar也是拥有属于自己的作用域,是局部作用域;在函数fn里面声明的变量b是局部变量,在外层Windows里声明的a、b是全局变量,全部变量的b和局部变量的b是没有关系,两者无论怎么变化、赋值都不会对彼此有影响,这样可以保证局部变量不会受到外部变量的污染; 当代码被执行时,会先解析代码,所有变量的声明都会被提前,然后再给予赋值;在执行 a + b 时,会在函数bar里寻找a和b的值,但在这个作用域找不到时,他就往上面的作用域找,在函数fn作用域找到b=2,不过函数fn里也没有a的值,就继续往上面的作用域找,直到找到最外层的a = 1;此时就可以计算 a + b了,在这寻找变量值的过程中,这条寻找链就是作用域链。 有这样的一段代码
for(var i=1; i<=5; i++) {
setTimeout( () => {
console.log(i)
})
}
打印出来全部都是6,为什么呢?正常来说一个循环下来,应该是打印出1,2,3,4,5;因为setTimeout是异步事件,当执行console.log的时候,早已经循环结束了;全局变量i也被赋值6,所以打印出来都是6,;那要怎么才能使它打印出来是1到5呢,这就可以使用闭包来实现了;上代码:
for(var i=1; i<=5; i++) {
setTimeout( ((i) => {
return function() {
console.log(i)
}
})(i))
}
- 使用自执行函数将每次循环的i的值传进去,闭包能够保护里面的变量避免被外层污染,所以外面的i无论怎么变,每个闭包里面的i的值都是原来的那个,所以它能够打印出1,2,3,4,5。
- 闭包有个问题就是使用完之后它不会被垃圾回收机制回收掉,它还会占用着内存,如果多了的话还会导致内存泄露(那得多少才会,在实际项目中基本上不考虑会出现);在我们使用完它之后记得要将它释放掉,也就是给它赋值null。