# 题目描述
闭包的一个小案例
每1秒输出一个j
, j
递增 —— j
初始值为1
1,2,3,4...
# 💪实现
下面这样写,就是一个for
循环执行三次,for
里面都是立即执行函数,所以直接放了三个setTimeout
到了任务队列里,同时,这三个都是设置的一秒后执行,
所以最后三条语句是同时输出,没有实现每1秒输出一次的需求
但此时
j
是闭包的,每次循环递增, 所以三条语句中的j
是实现了需求的,
for(var i = 0; i < 3; i ++){
((j) => {
setTimeout(() => {
console.log("第" + j + "次");
}, 1000);
})(i);
}
1
2
3
4
5
6
7
2
3
4
5
6
7
所以要控制三条语句按1秒的间隔输出,那就要在setTimeout
的执行时间上做文章了
for (let i = 1; i <= 4; i++) {
((j) => {
setTimeout(() => {
console.log(j);
}, j * 1000);
})(i);
}
1
2
3
4
5
6
7
2
3
4
5
6
7
上述的代码就可以实现我们的需求了~
# 扩展
下面的代码输出 1,2,3,4
,每次输出间隔一秒
TIP
因为let绑定 for 循环,let有自己的作用域块,会将其重新绑定到每一次的迭代中,保证每次迭代结束都会重新赋值
for( let i = 1; i <= 4; i ++){
setTimeout(() => {
console.log(i);
}, i * 1000);
}
1
2
3
4
5
2
3
4
5
但下面的代码输出5,5,5,5
,每次输出间隔一秒
TIP
var
没有自己的作用域块,所以循环变量就会后一个覆盖前一个,循环完毕只有一个值输出 —— 也就是最后一次i的值;
for (var i = 1; i <= 4; i++) {
setTimeout(() => {
console.log(i);
}, i * 1000);
}
1
2
3
4
5
2
3
4
5
# ✋ 手写一个闭包
- 闭包(Closures)是一个能够读取其他函数内部变量的函数
- 优点:使外部能访问到局部的东西 —— 让外部通过子函数来访问该函数里的局部变量
- 缺点:使用不当容易造成内存泄漏的问题
console.log("请输入a: ");
const a = Number(readline());
console.log("请输入a: ");
const b = Number(readline());
function myClosures(a) {
let inside = a;
return () => {
return inside + b;
};
}
console.log("a + b = ", myClosures(a)(b));
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
再稍微扩展一下 —— 可以实现公共、私有作用域控制
既然闭包可以对外提供访问内容变量的方式,就可以用这个特点实现类似 public private 作用域的需求
代码如下所示 👇
// 实现private对象
// 外部是访问不到data这个对象的
// 可以使用该data对象来存储一些私有的数据 —— 键值对的形式
var mydata = (function () {
var data = {};
return function (key, val) {
if (val === undefined) {
console.log("data: ", data);
return data[key];
} else {
data[key] = val;
console.log("data: ", data);
return data[key];
}
};
})();
console.log(mydata("x")); // data没有"x"这个key, 返回undefined
console.log(mydata("x", 1)); // 在data对象中设置一个键值对,"x" = 1, 然后返回"x"对应的val
console.log(mydata("x")); // data中有"x"对应的val, 直接返回对应val的值
/**
data: {}
undefined
data: { x: 1 }
1
data: { x: 1 }
1
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
闭包的四个应用场景
- 防抖
- 节流
- 封装私有变量
- 模拟私有方法