# 题目描述

闭包的一个小案例

每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

所以要控制三条语句按1秒的间隔输出,那就要在setTimeout的执行时间上做文章了

for (let i = 1; i <= 4; i++) {
  ((j) => {
    setTimeout(() => {
      console.log(j);
    }, j * 1000);
  })(i);
}
1
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

但下面的代码输出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

# ✋ 手写一个闭包

  • 闭包(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

再稍微扩展一下 —— 可以实现公共、私有作用域控制

既然闭包可以对外提供访问内容变量的方式,就可以用这个特点实现类似 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

闭包的四个应用场景

  1. 防抖
  2. 节流
  3. 封装私有变量
  4. 模拟私有方法