Featured image of post 简单了解 JavaScript 闭包

简单了解 JavaScript 闭包

闭包是 JavaScript 中一个非常重要的,而且是其中最具特色的概念之一。让我们一起了解一下什么是闭包以及它为什么如此重要。

什么是闭包?

根据 MDN 对于闭包的解释:

闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在 JavaScript 中,闭包会随着函数的创建而被同时创建。

闭包的实质是一个函数可以访问其外部作用域的变量,即使这个函数在其外部作用域已经退出。这种特性使得闭包能够在函数调用之间保留状态,实现跨函数的数据传递。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
function outer() {
  var outerVar = '外部作用域的变量'

  function inner() {
    console.log(outerVar) // inner 函数可以访问 outer 函数中的变量
  }

  return inner
}

var closureFunc = outer()
closureFunc() // 输出 "外部作用域的变量"

在上面的例子中,inner 函数形成了一个闭包,它可以访问 outer 函数中的 outerVar 变量,即使 outer 函数已经执行完毕并且 outer 函数的执行上下文已经出栈。这是因为 inner 函数继续保持对 outer 函数作用域的引用,这就是闭包的本质。

闭包的工作原理

作用域链(Scope Chain)

要理解闭包的工作原理,需要了解 JavaScript 的作用域链机制。

JavaScript 中的作用域链是一个从函数内部到外部作用域的链式结构。当一个函数内部引用外部变量时,JavaScript 引擎会从内部函数开始,沿着作用域链向上查找,直到找到该变量的定义为止。作用域链的查找顺序是:首先查找函数内部的局部变量,然后是其外部祖先函数的局部变量,最后是全局作用域。

变量提升(Variable Hoisting)

JavaScript 中,变量提升是指变量在声明后,其作用域会向上提升至最近的函数外部作用域。这意味着即使在一个函数内部声明了一个外部变量,JavaScript 引擎也会在函数外部为其创建一个全局变量。因此,当内部函数引用了外部变量时,实际上是在引用全局变量。

闭包的实现

闭包的实现依赖于作用域链和变量提升。当一个内部函数引用了外部变量时,JavaScript 引擎会在内部函数中创建一个对该外部变量的引用。当内部函数执行完毕,其作用域消失,但内部函数对外部变量的引用仍然存在。此时,如果外部函数继续执行,其作用域链中的外部变量会被提升,从而使得内部函数引用的外部变量得以保留。

闭包的实际应用

封装数据

一个常见的用途是通过闭包创建私有变量,以实现数据的封装和保护。这有助于防止其他代码意外地修改或访问数据。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
function createCounter() {
  var count = 0

  return {
    increment: function () {
      count++
    },
    decrement: function () {
      count--
    },
    getValue: function () {
      return count
    },
  }
}

var counter = createCounter()
counter.increment()
counter.increment()
console.log(counter.getValue()) // 输出 2

在这个示例中,count 变量是私有的,只能通过返回的对象中的方法进行访问和修改,从而确保数据的封装性和隐私性。

延迟执行

闭包还可以用于创建延迟执行的函数,例如在事件处理程序中。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function createDelayedFunction(message, delay) {
  return function () {
    setTimeout(function () {
      console.log(message)
    }, delay)
  }
}

var delayedFunc = createDelayedFunction('延迟消息', 2000)
delayedFunc() // 2 秒后输出 "延迟消息"

在这里,createDelayedFunction 函数返回一个闭包,它可以延迟执行一段代码,以便在指定的时间后输出消息。

参考资料