简单了解 JavaScript 闭包

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

什么是闭包?

根据 MDN 对于闭包的解释:

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

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

javascript 复制代码
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 引擎会在内部函数中创建一个对该外部变量的引用。当内部函数执行完毕,其作用域消失,但内部函数对外部变量的引用仍然存在。此时,如果外部函数继续执行,其作用域链中的外部变量会被提升,从而使得内部函数引用的外部变量得以保留。

闭包的实际应用

封装数据

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

javascript 复制代码
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 变量是私有的,只能通过返回的对象中的方法进行访问和修改,从而确保数据的封装性和隐私性。

延迟执行

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

javascript 复制代码
function createDelayedFunction(message, delay) {
  return function () {
    setTimeout(function () {
      console.log(message)
    }, delay)
  }
}

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

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

参考资料

相关推荐
tedcloud1235 小时前
UI-TARS-desktop部署教程:构建AI桌面自动化系统
服务器·前端·人工智能·ui·自动化·github
UXbot8 小时前
AI原型设计工具如何支持团队协作与快速迭代
前端·交互·个人开发·ai编程·原型模式
ZC跨境爬虫9 小时前
跟着MDN学HTML_day_48:(Node接口)
前端·javascript·ui·html·音视频
PieroPc10 小时前
CAMWATCH — 局域网摄像头监控系统 Fastapi + html
前端·python·html·fastapi·监控
巴巴博一12 小时前
2026 最新:Trae / Cursor 一键接入 taste-skill 完整教程(让 AI 前端告别“AI 味”)
前端·ai·ai编程
kyriewen12 小时前
半夜三点线上崩了,AI替我背了锅——用AI排错,五分钟定位三年老bug
前端·javascript·ai编程
kyriewen12 小时前
我让 AI 当了 24 小时全年无休的“毒舌考官”
前端·ci/cd·ai编程
hexu_blog12 小时前
vue+java实现图片批量压缩
java·前端·vue.js
IT_陈寒12 小时前
为什么你应该学习JavaScript?
前端·人工智能·后端