当前位置: 首页 > news >正文

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. 使用注意:避免内存泄漏,不滥用闭包,根据场景选择最优方案。
http://www.jsqmd.com/news/289934/

相关文章:

  • 救命神器10个AI论文软件,MBA轻松搞定毕业论文!
  • 苏州装修大揭秘!这几家公司凭什么脱颖而出?
  • 2026年修补料品牌TOP10推荐榜单,帮你找到最值得的修补料砂浆厂家
  • 2026年1月四川清洁用品、清洁工具、拖把、尘推、垃圾袋等制造厂家企业推荐报告
  • 2026年1月滚针轴承推荐榜:五家值得信赖的国产厂商深度解读
  • 考研集训营怎么选?盘点实力机构
  • 苏州装修公司大揭秘!这些排名靠前的公司你知道几家?
  • 共探设计家居新风向,菲浦斯助力江西商会设计产业分会年终盛典圆满举行
  • 动态类名在 <swiper-slide 的复制项中没有起作用的解决方法
  • 哪个牌子的静脉曲张袜好用?medi迈迪静脉曲张袜专业之选
  • 除甲醛智商税避坑指南:2025年十大真有效产品
  • 专精特新培育:从政策红利到能力红利的系统跃迁之路
  • 专知智库:以数据要素为核心引擎,赋能专精特新企业生产力与产品力双重跃迁
  • 成都余行专利代理事务所:专精特新企业知识产权全流程战略护航专家
  • 余行补位方法论:同步提升市场竞争力与专利授权率的双核引擎
  • 吐血推荐!自考AI论文软件TOP9:选对工具轻松过关
  • 余行补位方法论:构建专精特新企业的“护城河飞轮”
  • 专精特新小巨人发展,为何必须依靠外脑?又该找谁?
  • 带pip的python2.x版本
  • 亲测好用9个AI论文写作软件,专科生轻松搞定毕业论文!
  • NMN哪个产品最好?NAD+哪个产品最好,2026细胞抗衰机制白皮书
  • Zemax光学设计偶次非球面优化技巧
  • 光学工程师就业方向推荐
  • Zemax光学设计MTF子午和弧矢分开大,
  • 小红书评论数据一键获取,item_reviewAPI接口讲解
  • 技术革新与办公效率革命:Nano Banana Pro、NotebookLM与ChatPPT的深度解析
  • MongoDB实现发布订阅机制
  • conda下安装cuda11.8和cudnn
  • 2026最新conda镜像源
  • GVHMR输出的.pt文件最全面分析