# 六.闭包

前言

  • 闭包有两部分组成,一个是当前的执行上下文 A,一个是在该执行上下文中创建的函数 B
  • 当 B 执行的时候引用了当前执行上下文 A 中的变量就会产生闭包
  • 当一个值失去引用的时候就会标记,被垃圾回收机制回收并释放空间
  • 闭包的本质就是在函数外部保持内部变量的引用,从而阻止垃圾回收
  • 调用栈并不会影响作用域链,函数调用栈是在执行时才确定,而作用域规则是在代码编译阶段就已经确定了
  • MDN 定义:闭包是指这样的作用域foo,它包含了一个函数fn,这个函数fn可以调用被这个作用域所封闭的变量a,函数等内容

# 1.认识闭包

  • Call Stack为当前的函数调用栈
  • Scope为当前正在被执行函数的作用域链
  • Local为当前的活动对象
function one() {
  var a = 1
  var b = 2
  function two() {
    var c = 3
    debugger
    console.log(a, c)
  }
  return two
}
let two = one()
two()
1
2
3
4
5
6
7
8
9
10
11
12
function one() {
  var a = 1
  var b = 2
  function two() {
    debugger
    console.log(a)
  }
  two()
}
one()
1
2
3
4
5
6
7
8
9
10

# 2.闭包优化

  • 中间没用到的变量闭包会被忽略
function one() {
  var a = 1
  function two() {
    var b = 2
    function three() {
      var c = 3
      debugger
      console.log(a, b, c)
    }
    three()
  }
  two()
}
one()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function one() {
  var a = 1
  function two() {
    var b = 2
    function three() {
      var c = 3
      debugger
      console.log(a, c)
    }
    three()
  }
  two()
}
one()
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 3.arguments

function log(a, b) {
  debugger
  console.log(a, b)
}
log(1, 2)
1
2
3
4
5

典型使用场景

  • Vue 源码中,编译函数生成后会保存在内存中,避免频繁编译时重新生成编译函数;派发更新函数同理
  • Webpack 源码中,编译函数生成后会保存起来,整个生命周期只执行一次