定义

一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包closure)。

闭包:函数 + 可以访问的自由变量

普通函数:如果它可以访问外层作用于的自由变量,那么这个函数就是一个闭包;

广义的角度:JavaScript中的函数都是闭包

狭义的角度:JavaScript中一个函数,如果访问了外层作用于的变量,那么它是一个闭包;

​ 出自于 coderwhy 大佬

作用:

1、实现数据私有

let count = 0
function fn () {
  count++
  console.log('fn函数被调用了' + count + '次')
}
fn() // count数据容易被修改
fn()
fn()
count = 10
fn() // fn函数被调用了11次

-------------------------------------------------------------

function fn () {
  let count = 0
  function add () {
    count++
    console.log('fn函数被调用了' + count + '次')
  }
  return add
}
const addFn = fn()
addFn() // fn函数被调用了1次
addFn() // fn函数被调用了2次
addFn() // fn函数被调用了3次
count = 10
addFn() // fn函数被调用了4次

2、解决 var 的全局变量在异步函数调用中的变化

for (**let** i = 0; i < 5; i++) { // let 是局部变量
  setTimeout(() => {
    console.log(i);
  }, 1000 * i);
}
//输出:0 1 2 3 4

for (**var** i = 0; i < 5; i++) { // var 是全局变量
  setTimeout(() => {
    console.log(i);
  }, 1000 * i);
}
// 输出: 5 5 5 5 5,5是因为最后i++跳出来的是5

// 使用闭包实现类似let的结果
for (var i = 0; i < 5; i++) {
  function f(i) {
    setTimeout(() => {
      console.log(i);
    }, 1000 * i);
  }
  f(i);
}
//输出:0 1 2 3 4

3、让这些变量的值始终保持在内存中,不被销毁

注意点:外部函数中,一般需要return来进行引用(内存才不会被释放)

销毁的方法:

  • 标记清除:从根部,全局出发,访问不到(无法触及)的内存空间,就会被自动回收
  • 释放内存,断开了对于之前内部函数的引用,对应的缓存的变量内容也会被释放掉

Reference

你不可不知道的 JavaScript 作用域和闭包 - 知乎 (zhihu.com)

学习Javascript闭包(Closure) - 阮一峰的网络日志 (ruanyifeng.com)

javasctipt.info | Variable scope, closure

JavaScript深入之闭包 #9