# 闭包

闭包是指有权访问另一个函数作用域中的变量的函数。闭包是就是函数中的函数,里面的函数可以访问外面函数的变量,外面的变量的是这个内部函数的一部分。

闭包的作用:

  1. 使用闭包可以访问函数中的变量。
  2. 可以使变量长期保存在内存中,生命周期比较长。

闭包不能滥用,否则会导致内存泄露,影响网页的性能。闭包使用完了后,要立即释放资源,将引用变量指向 null。

使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。

闭包有三个特性:

  1. 函数嵌套函数
  2. 函数内部可以引用外部的参数和变量
  3. 参数和变量不会被垃圾回收机制回收

# 闭包的使用场景

  • 创建特权方法用于访问控制
  • 事件处理程序及回调
  • 利用闭包实现数据私有化或模拟私有方法。这个方式也称为模块模式(module pattern)
  • 部分参数函数(partial applications)柯里化(currying)
  • 封装变量,收敛权限。在函数外面根本没有接口修改私有变量和函数,保证了数据的安全。
  • cached 对象储存。
  • 封装私有变量

# 循环中使用闭包解决 var 定义函数的问题

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

解决方法有 3 种

第一种,使用立即执行函数方式

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

第二种,使用 ES6 的let, 因为对于 let 来说,他会创建一个块级作用域

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

相当于

{ // 形成块级作用域
  let i = 0
  {
    let ii = i
    setTimeout( function timer() {
        console.log( ii );
    }, i*1000 );
  }
  i++
  {
    let ii = i
  }
  i++
  {
    let ii = i
  }
  ...
}

第三种,使用 setTimeout 的第三个参数

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