闭包:从入门到“顿悟”的奇幻之旅

闭包:从入门到"顿悟"的奇幻之旅

前言:闭包是个啥?

闭包是JavaScript中最迷人的概念之一,也是让无数开发者又爱又恨的特性。简单来说,闭包就是个函数------但别急着关页面,这个函数有点特别!它能记住并访问自己被定义时的环境,哪怕这个函数在别处被执行。就像一个人无论走多远,都能记住家乡的味道。

闭包之所以重要,是因为它:

  • 打破了函数作用域的"次元壁"
  • 创造了JavaScript中的"私有变量"
  • 是现代前端框架和模块系统的基石

准备好开始这段奇妙的闭包之旅了吗?让我们从最基础的概念出发,逐步揭开闭包的神秘面纱!

正文:闭包的三重境界

第一重:认识闭包

闭包是个能访问其他函数内部变量的函数。就像特工可以访问上级的秘密档案一样。

javascript 复制代码
function 创建计数器() {
  let 计数 = 0 // 这是"秘密档案"
  return function() {
    计数++ // 内部函数访问外部变量
    return 计数
  }
}

const 我的计数器 = 创建计数器()
console.log(我的计数器()) // 1
console.log(我的计数器()) // 2

这里的关键点:

  1. 内部函数访问了外部函数的变量计数
  2. 即使外部函数执行完毕,计数依然被保留
  3. 每次调用我的计数器(),都能访问和修改同一个计数

第二重:闭包的工作原理

为什么闭包能记住变量?这要从JavaScript的"记忆宫殿"说起:

  1. 作用域链:每个函数都有自己的小本本(作用域),找不到变量时就向上级要
  2. 变量保存:被闭包引用的变量会特殊对待,不会被垃圾回收
  3. \[Scopes]属性:函数内部有个隐藏属性,保存着它需要的所有变量

第三重:闭包的七十二变

闭包在JavaScript中变化多端,常见形态包括:

  1. 返回函数(经典形态)
javascript 复制代码
function 创建问候语(名字) {
  return function() {
    console.log(`你好, ${名字}!`)
  }
}
  1. 异步回调(隐身形态)
javascript 复制代码
setTimeout(function() {
  console.log('我是隐身的闭包!')
}, 1000)
  1. IIFE(立即执行函数)
javascript 复制代码
(function(全局) {
  // 这里也是个闭包!
})(window)
  1. 模块模式(高级形态)
javascript 复制代码
const 我的模块 = (function() {
  const 私有变量 = '秘密'
  return {
    获取秘密: function() { return 私有变量 }
  }
})()

特别章节:闭包面试必考题

问题:为什么这段代码输出五个6?

javascript 复制代码
for(var i = 1; i <= 5; i++) {
  setTimeout(function() {
    console.log(i)
  }, 0)
}

解答 :因为setTimeout是异步的,等它执行时循环已经结束,而所有回调共享同一个i(值为6)

三种解决方案

  1. IIFE大法 - 给每个循环创建独立作用域
javascript 复制代码
for(var i = 1; i <= 5; i++) {
  (function(j) {
    setTimeout(function() {
      console.log(j)
    }, 0)
  })(i)
}
  1. let救星 - 块级作用域解决问题
javascript 复制代码
for(let i = 1; i <= 5; i++) {
  setTimeout(function() {
    console.log(i)
  }, 0)
}
  1. setTimeout第三参数 - 直接传递值
javascript 复制代码
for(var i = 1; i <= 5; i++) {
  setTimeout(function(j) {
    console.log(j)
  }, 0, i)
}

总结:闭包之道

闭包就像JavaScript中的"记忆面包",让函数能够记住自己诞生时的环境。通过本文的探索,我们了解到:

  1. 闭包的本质:函数 + 创建时的环境

  2. 闭包的用途

    • 创建私有变量
    • 实现函数工厂
    • 模块化开发
    • 处理异步回调
  3. 注意事项

    • 警惕内存泄漏(不再使用的闭包要及时释放)
    • 理解循环中的闭包陷阱
    • 合理使用现代语法(let/const)简化闭包

记住,闭包不是洪水猛兽,而是JavaScript赋予我们的超能力。正如一位智者所说:"理解了闭包,你就理解了JavaScript的一半。"现在,带着这份理解去创造更多精彩的代码吧!

闭包如同人生:我们带着过去的记忆,走向未来的执行上下文。重要的不是记住多少,而是如何善用这些记忆。

相关推荐
sbjdhjd6 小时前
Redis 主从复制、哨兵高可用与 Cluster 集群部署实验手册
运维·前端·redis·云原生·开源·bootstrap·html
乐兮创想 小林6 小时前
企业官网移动端性能优化实战:从 Core Web Vitals 到图片/CDN/响应式的工程清单
前端·性能优化·网站建设·北京网站建设公司
前端一小卒7 小时前
不手写代码的第 30 天,我才明白前端这个岗位还剩什么
前端·javascript·ai编程
Ajie'Blog7 小时前
Copilot Agent Tasks API 开放:AI 编程开始进入后台任务时代
服务器·前端·javascript·人工智能·copilot·ai编程
老毛肚7 小时前
jeecgboot vue TS & 模板化 04
前端·javascript·vue.js
AI_零食9 小时前
鸿蒙PC Electron跨平台应用开发:24时区时间表应用详解
前端·华为·electron·开源·harmonyos·鸿蒙
Electrolux9 小时前
[onlyoffice-v9]纯前端怎么实现编辑预览office
前端·javascript·github
码云之上9 小时前
聊聊如何设计一个高效、稳定的 Node.js 接入层
前端·后端·node.js
kyriewen10 小时前
我读了一遍 Babel 编译后的 async/await,终于搞懂了它的原理(附 20 行手写实现)
前端·javascript·面试
IT_陈寒10 小时前
Vite项目build后路由404了?你可能漏了这个小配置
前端·人工智能·后端