news 2026/3/25 3:56:20

01_闭包原理:从变量作用域到闭包的 3 个实际用途(以计数器为例)【包含课程视频】

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
01_闭包原理:从变量作用域到闭包的 3 个实际用途(以计数器为例)【包含课程视频】

闭包原理:从变量作用域到闭包的 3 个实际用途(以计数器为例)

点击这里观看课程

一、前置知识:理解变量作用域(闭包的基础)

要理解闭包,首先要搞清楚变量作用域——变量能被访问的范围,主要分为两种:

1. 全局作用域

  • 定义在函数外部的变量,整个程序都能访问和修改,容易造成变量污染。
  • 示例:
    letcount=0;// 全局变量functionadd(){count++;console.log(count);}add();// 输出 1add();// 输出 2count=100;// 全局变量可被随意修改,导致计数器逻辑混乱add();// 输出 101(不符合计数器预期)

2. 函数作用域(局部作用域)

  • 定义在函数内部的变量,只有函数内部能访问,外部无法直接修改,更安全,但函数执行后变量会被销毁。
  • 示例:
    functionadd(){letcount=0;// 局部变量count++;console.log(count);}add();// 输出 1(函数执行后 count 被销毁)add();// 输出 1(重新创建 count 并赋值 0)

问题:全局变量不安全,局部变量无法保留状态——闭包就是解决这个矛盾的核心方案。

二、闭包的核心原理

1. 闭包的定义

闭包是指内层函数可以访问外层函数作用域中的变量,即使外层函数已经执行完毕。简单来说:

  • 外层函数包裹内层函数;
  • 内层函数引用外层函数的局部变量;
  • 外层函数返回内层函数。

此时,外层函数的作用域不会被销毁,变量会被“保留”,且外部无法直接修改,只能通过内层函数操作。

2. 闭包的核心逻辑(以计数器为例)

// 外层函数:创建计数器的“容器”functioncreateCounter(){letcount=0;// 外层函数的局部变量,被内层函数引用// 内层函数:操作局部变量的逻辑functionincrement(){count++;returncount;}returnincrement;// 返回内层函数,形成闭包}// 使用闭包创建计数器constcounter=createCounter();console.log(counter());// 输出 1(count 保留了上一次的状态)console.log(counter());// 输出 2console.log(counter());// 输出 3// 无法直接修改 count,保证数据安全console.log(count);// 报错:count is not defined

原理拆解

  1. 执行createCounter()时,创建局部变量count和函数increment
  2. 返回increment函数并赋值给counter,此时createCounter执行完毕,但因为increment引用了count,所以count不会被垃圾回收;
  3. 每次调用counter(),都会访问并修改同一个count,实现状态保留。

三、闭包的 3 个实际用途

用途 1:保留函数状态(核心用途,如计数器/累加器)

除了基础计数器,还可以扩展为带初始值的计数器,适配更多场景:

functioncreateCounter(initialValue=0){letcount=initialValue;return{increment:()=>{count++;returncount;},decrement:()=>{count--;returncount;},reset:()=>{count=initialValue;returncount;},getCount:()=>count// 只读访问,避免直接修改};}// 示例:创建初始值为 10 的计数器constmyCounter=createCounter(10);console.log(myCounter.increment());// 11console.log(myCounter.decrement());// 10console.log(myCounter.reset());// 10console.log(myCounter.getCount());// 10

用途 2:封装私有变量(模拟“私有属性/方法”)

JavaScript 原生没有private关键字,闭包可以实现变量私有化,只暴露指定的操作方法:

functioncreatePerson(name){// 私有变量:外部无法直接访问letage=0;// 暴露的公共方法return{getName:()=>name,growUp:()=>{age++;returnage;},getAge:()=>age};}constperson=createPerson("小明");console.log(person.getName());// 输出 小明console.log(person.growUp());// 输出 1console.log(person.age);// 输出 undefined(私有变量无法直接访问)

用途 3:防抖/节流(前端高频场景,利用闭包保留状态)

闭包可以保留防抖/节流函数中的定时器、上次执行时间等状态,避免全局变量污染:

// 防抖函数:频繁触发时,只执行最后一次functiondebounce(fn,delay){lettimer=null;// 闭包保留定时器状态returnfunction(...args){clearTimeout(timer);// 清除上一次的定时器timer=setTimeout(()=>{fn.apply(this,args);},delay);};}// 用法:监听窗口resize,避免频繁触发window.addEventListener("resize",debounce(()=>{console.log("窗口大小改变了");},500));

四、闭包的注意事项

  1. 内存泄漏风险:闭包会保留外层作用域的变量,若长期不释放(如全局变量引用闭包),可能导致内存占用过高。解决:不再使用时,手动将闭包引用赋值为null(如counter = null)。
  2. 性能问题:闭包的作用域链查找比普通变量慢,高频执行的代码需谨慎使用。
  3. 避免滥用:不是所有场景都需要闭包,简单的状态管理可优先用其他方式(如 React 的 useState、Vue 的 ref)。

总结

  1. 闭包核心:内层函数引用外层函数的局部变量,使外层变量在函数执行后不被销毁,实现状态保留和私有化;
  2. 核心用途:保留函数状态(计数器)、封装私有变量、实现防抖/节流等高频前端功能;
  3. 使用注意:避免内存泄漏,不滥用闭包,根据场景选择最优方案。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/24 4:18:44

Java基于Spring Boot+Vue的学业导师管理系统的设计与实现

所需该项目可以在最下面查看联系方式,为防止迷路可以收藏文章,以防后期找不到 项目介绍 在当今高等教育体系中,本科生学业导师制度已成为提升教学质量、促进学生个性化发展的重要途径。然而,随着高校扩招和学生人数的激增&#…

作者头像 李华
网站建设 2026/3/14 10:38:19

亲测好用9个AI论文写作软件,专科生轻松搞定毕业论文!

亲测好用9个AI论文写作软件,专科生轻松搞定毕业论文! 专科生的论文写作救星,AI 工具如何改变你的学习节奏? 在当今这个信息爆炸的时代,学术写作早已不再是少数人的专属。对于专科生而言,撰写一篇合格的毕业…

作者头像 李华
网站建设 2026/3/12 21:00:41

专精特新小巨人发展,为何必须依靠外脑?又该找谁?

专精特新小巨人发展,为何必须依靠外脑?又该找谁?专精特新小巨人企业正站在发展的关键节点:一方面拥有核心技术优势,另一方面却面临从“技术冠军”向“生态领袖”跃迁的复杂挑战。在这个阶段,仅靠企业内部力…

作者头像 李华
网站建设 2026/3/24 2:46:12

成都余行专利代理事务所:专精特新企业知识产权全流程战略护航专家

成都余行专利代理事务所:专精特新企业知识产权全流程战略护航专家 在专精特新企业的发展征程中,知识产权不仅是技术创新的保护伞,更是企业构建核心竞争力和生态话语权的战略武器。然而,专利工作绝非简单的“申请-授权”线性流程&…

作者头像 李华
网站建设 2026/3/17 9:36:32

余行补位方法论:同步提升市场竞争力与专利授权率的双核引擎

余行补位方法论:同步提升市场竞争力与专利授权率的双核引擎在专精特新企业的发展实践中,市场竞争力与专利授权率常常被视为两个独立的目标:前者关乎商业成功,后者关乎法律保护。然而,成都专知利乎数字科技有限公司提出…

作者头像 李华
网站建设 2026/3/22 5:56:23

【收藏必看】告别提示词地狱!技能工程引领AI开发新范式

Agent Skills技术正引领AI开发从"提示词博弈"向标准化"技能工程"转变。这种可移植技能包通过三层结构(核心定义层、执行支撑层、资源依赖层)将专业开发流程标准化,已在Gemini CLI、Antigravity IDE等主流开发工具中实现落…

作者头像 李华