闭包

闭包:函数 A 内部有一个函数 B,函数 B 可以访问到函数 A 中的变量,那么函数 B 就是闭包。一个作用域可以访问另外一个函数的局部变量。

闭包的作用:1.可以读取函数内部的变量,延长变量的作用域  2.让这些变量始终保持在内存中,即闭包可以使得它诞生环境一直存在

1 function A() {
2     let a = 1
3     window.B = function() {
4         console.log(a)
5     }
6 }
7 A()
8 B() // 1

这里B就是闭包,单纯地说闭包就是函数嵌套了函数,然后返回一个函数,是不完整的,上面的例子很好地反驳了。

 1 function f1() {
 2     let a = 1
 3 
 4     function f2() {
 5         console.log(a);
 6     }
 7     return f2;
 8 }
 9 var res = f1();
10 res(); // 1

这里闭包就是函数f2,能够读取f1函数内部的变量(闭包就是一个能读取其他函数内部变量的一个函数,简单来说就是一个函数)

1 function create(start) {
2     return function() {
3         console.log(start++);
4     }
5 }
6 var inc = create(5);
7 inc(); // 5
8 inc(); // 6
9 inc(); // 7

这里就是闭包使得内部变量记住了上一次调用的结果。

 

 

经典面试题,循环中使用闭包解决 `var` 定义函数的问题

1 for (var i = 0; i < 6; i++) {
2     setTimeout(function timer() {
3         console.log(i);
4     }, i * 1000)
5 }

首先因为 setTimeout 是个异步函数,所以会先把循环全部执行完毕,这时候 i 就是 6 了,所以会输出一堆 6。(同理,click等点击事件是回调函数,for循环是同步任务,就会先把循环执行完毕)

解决办法有三种,第一种是使用闭包的方式

1 for (var i = 0; i < 6; i++) {
2     (function(j) {
3         setTimeout(function timer() {
4             console.log(j);
5         }, j * 1000)
6     })(i)
7 }

在上述代码中,我们首先使用了立即执行函数将 i 传入函数内部,这个时候值就被固定在了参数 j 上面不会改变,当下次执行 timer 这个闭包的时候,就可以使用外部函数的变量 j,从而达到目的。

第二种就是使用 setTimeout 的第三个参数,这个参数会被当成 timer 函数的参数传入。

1 for (var i = 0; i < 6; i++) {
2     setTimeout(function timer(j) {
3         console.log(j);
4     }, i * 1000, i)
5 
6 }

第三种就是使用 let 定义 i 了来解决问题了,这个也是最为推荐的方式

1 for (let i = 0; i < 6; i++) {
2     setTimeout(function timer() {
3         console.log(i);
4     }, i * 1000)
5 }

 

posted @ 2020-02-06 15:36  heyztadxw  阅读(120)  评论(0编辑  收藏  举报