“闭包到底是什么?90% 的前端开发者都没真正搞懂!”
myzbx 2025-09-06 08:22 7 浏览
前言
在 JavaScript 的世界里,闭包(Closure)是一个既常见又容易被误解的概念。无论你是初学者还是有经验的开发者,闭包都在你编写代码的过程中扮演着重要角色。本文将用通俗易懂的语言,带你深入理解闭包的本质、工作原理、实际应用场景以及常见的陷阱和最佳实践。
一、什么是闭包?
闭包,简单来说,就是函数能够“记住”并访问它定义时的作用域,即使这个函数在其作用域之外被调用。
更正式一点,闭包是指那些能够访问自由变量的函数。自由变量指的是在函数中使用,但既不是函数参数也不是函数的局部变量的变量。
例子
function makeCounter() {
let count = 0;
return function() {
count++;
return count;
}
}
const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
在上面的例子中,counter 是一个闭包。它可以访问 makeCounter 作用域中的 count 变量,即使 makeCounter 已经执行完毕。
二、闭包的工作原理
1. 作用域链
JavaScript 中的每个函数在创建时都会生成一个作用域链。函数可以访问其自身作用域、父级作用域以及全局作用域中的变量。
2. 闭包的本质
当一个函数返回另一个函数时,返回的函数依然“持有”对其父作用域变量的引用。这种机制就是闭包的本质。
3. 内存管理
由于闭包会持有对外部变量的引用,这些变量不会被垃圾回收机制回收,直到闭包本身被销毁。
三、闭包的实际应用场景
1. 数据私有化
闭包可以用来模拟私有变量,实现数据的封装。
function Person(name) {
let age = 0;
return {
getName: function() { return name; },
getAge: function() { return age; },
grow: function() { age++; }
}
}
const p = Person('Tom');
p.grow();
console.log(p.getAge()); // 1
2. 工厂函数
闭包常用于工厂函数,动态生成带有私有状态的函数
function multiplier(factor) {
return function(x) {
return x * factor;
}
}
const double = multiplier(2);
console.log(double(5)); // 10
3. 回调与异步编程
闭包在事件处理、定时器、Promise 等异步编程中非常常见。
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 3, 3, 3
}, 100);
}
如果想输出 0, 1, 2,可以用闭包保存每次的 i:
for (var i = 0; i < 3; i++) {
(function(j) {
setTimeout(function() {
console.log(j); // 0, 1, 2
}, 100);
})(i);
}
四、闭包的常见陷阱
1. 内存泄漏
闭包会导致外部变量无法被及时回收,若不注意,可能造成内存泄漏。
建议: 不再需要闭包时,将其置为 null,或避免不必要的闭包。
2. 变量共享问题
如上面 setTimeout 的例子,循环中的闭包会共享同一个变量,导致输出不符合预期。可以通过 IIFE(立即执行函数表达式)或 let 块级作用域解决。
五、闭包的最佳实践
- 合理使用闭包:不要滥用闭包,只有在需要数据私有化或延迟执行时才使用。
- 避免内存泄漏:及时释放不再需要的闭包引用。
- 使用 let/const:ES6 之后,优先使用 let/const 声明变量,减少闭包带来的变量共享问题。
- 代码可读性:为闭包函数命名,提升代码可读性和可维护性。
六、面试中的闭包
闭包是前端面试的高频考点。常见问题有:
- 闭包的定义和原理
- 闭包的应用场景
- 如何避免闭包带来的问题
- 实现一个计数器/私有变量等
七、总结
闭包是 JavaScript 的核心特性之一。它让我们能够实现数据私有化、工厂函数、回调等强大功能,但也带来了内存泄漏和变量共享等问题。理解闭包的原理,掌握其应用场景,并遵循最佳实践,才能写出高质量、健壮的 JavaScript 代码。
一句话总结: 闭包让函数拥有“记忆”,是 JS 编程的利器,但也需谨慎使用。
相关推荐
- 微信又双叒叕更新了!这次是安卓版
-
澎湃新闻综合报道近日安卓版微信正式更新了8.0.10版主要有四大更新日常使用起来会更加方便一起来看看吧1朋友圈视频封面在此之前,朋友圈背景一直只能放静态图片,但此次更新后,可以从视频号中选择一段...
- 镜子里的你和照片里的你,哪个更真实?
-
不知道大家有没有这样的经历。聚餐、团建……一群人拍合照,拍完之后,我们满心期待地放大照片,却惊慌失措地发现——怎么自己又被拍得这么丑!但这时,别人总是会说道——「这就是你平常的样子啊。」可是,我们平时...
- 歼20战斗机现身珠海,首次公开静态展示,体现解放军的自信和强大
-
日本航空自卫队在9月份举行了三泽基地开发日活动,期间出动12架F-35A闪电II战斗机进行了公开展示,不过仅仅是编队通场飞过而已。日本航空自卫队仅仅动用1架F-35A战斗机进行了机动飞行表演,从公开的...
- Java类初始化阶段深度解析:执行顺序与线程安全
-
一、初始化阶段核心机制二、分步详解与代码验证1.初始化触发条件主动使用场景:publicclassInitTrigger{static{System.out.pr...
- 深入剖析 Java 类加载机制:原理、优化与实践
-
作为Java开发者,你是否遇到过这样的场景:线上服务突然抛出NoClassDefFoundError,但本地调试却一切正常;或者明明引入了依赖JAR,却始终报ClassNotFoundExcep...
- SUID/SGID是啥?如何让普通用户拥有root的能力?
-
原文链接:「链接」在Linux系统中,权限控制是一项至关重要的安全机制。除了常见的r(读)、w(写)和x(执行)权限外,还有三种特殊权限位常被忽视:SUID(SetUserID)、SGID...
- 数码宝贝新世纪:SP奥米加兽AS情报泄露,是否也是强力辅助?
-
大家好!我是小飉[liáo],欢迎来阅!情怀手游《数码宝贝新世纪》官方不按套路出牌,这次公布的入围测试的人员名单,但是并没有公布SP奥米加兽AS的能力情报,还好广大网友给力。次日,在论坛,以及...
- 抽象类(abstract class)与接口(interface)
-
A.核心概念1.抽象类-定义:带有abstract修饰符的类,不能被实例化,用于定义一组方法签名和可选的部分公共实现。-特性:-可以包含字段、构造函数、已实现的方法(带方法体)和抽象方法(...
- S39结束时间确定,新赛季段位继承公布,大量皮肤在7月初集体上线
-
文/静海君如果说之前都还是猜测的话,那游戏内的一个变动,基本100%确定了新赛季(S40)的开启时间。新赛季的开启时间关于新赛季的开启时间,目前主要有两个线索。第一个关于新赛季开启时间的线索是「游戏内...
- 一篇文章掌握整个JVM,JVM超详细解析!!!
-
不懂JVM看完这一篇文章你就会非常懂了,文章很长,非常详细!!!先想想一些问题1我们开发人员编写的Java代码是怎么让电脑认识的首先先了解电脑是二进制的系统,他只认识01010101比如我们经常要...
- 项目用 JDK17 后,bug 少了、速度快了!这 4 个好处太实在
-
别再死守JDK8了!去年把电商项目升级到JDK17,团队直接爽翻:代码量少写1/3,大促再也不卡顿,运维半夜不call人,连测试都夸bug少了。今天就说真话,JDK17在项目里的4...
- 法定继承有顺序:在法定继承人中,谁应该优先继承?
-
免费问律师_法律咨询免费24小时律师在线解答-法临网“父母去世没留遗嘱,兄弟姐妹争遗产闹上法庭!”法定继承中,谁优先拿财产?《民法典》明确“顺序+份额”规则,一文说清关键点,避免家庭内耗!一、法定...
- 前端必会:ES5寄生继承 vs ES6 Class继承
-
大家好,我是谦!说到继承,估计不少前端开发者都踩过坑。尤其是在ES5到ES6的过渡阶段,我们写代码时常常被问到:“你用的是原型继承还是Class继承?”再加上面试官特别喜欢追问底层实现——...
- 子女入了外籍能否继承父母国内的房产呢?
-
大家好,这里是家理范律,专注遗产继承、婚姻家事领域!-很多加入外籍的朋友都纠结:自己还能继承国内父母的房产吗?答案是可以继承,但流程远比想象复杂!-真实案例:美籍华人张先生,拿着父母在加州公证的遗嘱回...
- J.A.C.S | 基于化学类型和靶点的基因组挖掘以寻找一种新的细菌肽脱甲酰酶天然产物抑制剂
-
大家好,今天推送的文章是2025年6月发表在JournaloftheAmericanChemicalSociety上的“Chemotype-andTarget-DrivenGenome...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 简介 (30)
- HTML 响应式设计 (31)
- HTML URL 编码 (32)
- HTML Web 服务器 (31)
- HTML 表单属性 (32)
- HTML 音频 (31)
- HTML5 支持 (33)
- HTML API (36)
- HTML 总结 (32)
- HTML 全局属性 (32)
- HTML 事件 (31)
- HTML 画布 (32)
- HTTP 方法 (30)
- 键盘快捷键 (30)
- CSS 语法 (35)
- CSS 轮廓宽度 (31)
- CSS 谷歌字体 (33)
- CSS 链接 (31)
- CSS 定位 (31)
- CSS 图片库 (32)
- CSS 图像精灵 (31)
- SVG 文本 (32)
- 时钟启动 (33)
- HTML 游戏 (34)
- JS Loop For (32)