闭包问题

Youky ... 2021-10-11 前端
  • JS
About 1 min

# 闭包问题

# 闭包的定义

有权访问另一个函数作用域中变量的函数

# 闭包产生的原因

当前作用域中有对父级作用域的引用

并不一定要通过返回函数的形式,也可以通过用外部变量保存对父级作用域的引用来体现。

# 闭包的使用场景

function Single(con){
    let flag = null;
    return function(){
        if(flag) return flag;
        else{
            flag = new con(...arguments);
            return flag;
        }
    }
}

const Person = Single(function(name, age){
    this.name = name;
    this.age = age;
})

let foo = new Person('foo', 21);
let bar = new Person('bar', 20);
console.log(foo === bar); // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  • 实现私有变量

const Foo = (function(){
    let sym = Symbol();
    return class Foo{
        constructor(name){
            this[sym] = name;
        }
        getName(){
            return this[sym];
        }
    }
})()
let foo = new Foo('foo');
console.log(foo.getName()) // 只能通过定义的方法获取私有变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 如何解决因闭包产生的循环输出问题

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

输出结果都是6的原因:setTimeout作为宏任务加入任务队列。同步任务执行结束执行内部回调时,向父级作用域查找i,而i此时已经变成6了。

解决方案:

  1. 使用let替换var,因为let创建的是块级变量
  2. 将i作为setTimeout的第三个参数传入
for(var i=1;i<=5;i++){
  setTimeout(function timer(j){
    console.log(j)
  }, 0, i)
}
1
2
3
4
5
  1. 使用IIFE(立即执行函数),把当前状态的i传入
for(var i = 1;i <= 5;i++){
  (function(j){
    setTimeout(function timer(){
      console.log(j)
    }, 0)
  })(i)
}
1
2
3
4
5
6
7
Last update: November 27, 2021 21:16
Contributors: youky7