网站首页 > 技术文章 正文
从一个for循环开始谈闭包
“麦克,我写了一段代码,但输出结果和我预期的不一致!”小白对着屏幕苦恼
“是吗代码给我看下”
“这是一个很经典的问题。
for循环是同步的,而onclick点击事件是异步触发的,当你点击onclick的时候for循环早就结束了,也就是说i已经是5了。那怎么办呢?你得用闭包啊,我帮你改造一下,我们利用闭包将每次循环的都封闭到一个独立的作用域中”
测试一下!
“果然可以了”小白用chrome浏览器进行了测试
麦克黑继续说道:“关于闭包我们 还可以有另一个种写法。”
测试结果和上次一样。
接下来我给你讲下闭包在开发中的作用和优缺点,你要注意哦,以下内容会在很多前端面试的过程中问到。
闭包在开发中会帮助我们闯到一个封闭的环境变量,避免局部变量暴漏在全局环境下。这样就避免了局部变量对全局的污染。但同时我们也经常会听到的一种说法就是要减少闭包的使用,因为闭包有可能会造成内存泄露。
为什么会造成内存泄露呢?
局部变量在我们使用完退出的时候就会解除对他的引用,然后从内存中推出。但如果使用闭包以后,局部变量就会被封闭在闭包的环境中,那么这个局部变量就会一直存在下去,无法回收,但这并不是内存泄露,仅仅是无法回收而已,如果需要回收,可以通过收到将变量设置为null,就实现了回收.
什么是内存泄露呢?
就比如一杯水,水满了就会溢出。 同理,内存溢出就是程序运行所需的内存大于可用内存,就出现内存溢出错误也叫内存泄露。也就是说如果内存中无法回收的变量过多,就会造成容易造成内存泄露。
容易造成内存溢出的情况
计时器的引用变量没有及时清除,
dom清空或删除时,事件未清除导致的内存泄漏
回调事件造成循环引用导致变量无法被回收
,监听事件没有移出都容易造成内存泄露。
追本溯源,我们先要了解一下JavaScript的内存垃圾回收机制
下面这段话引自《JavaScript权威指南(第四版)》
由于字符串、对象和数组没有固定大小,所有当他们的大小已知时,才能对他们进行动态的存储分配。JavaScript程序每次创建字符串、数组或对象时,解释器都必须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便他们能够被再用,否则,JavaScript的解释器将会消耗完系统中所有可用的内存,造成系统崩溃。
现在各大浏览器通常用采用的垃圾回收有两种方法
标记清除
这是javascript中最常用的垃圾回收方式。当变量进入执行环境是,就标记这个变量为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到他们。当变量离开环境时,则将其标记为“离开环境”。
垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后。垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间。
引用计数
不太常见的垃圾回收策略是引用计数。引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数就减1。当这个引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其所占的内存空间给收回来。这样,垃圾收集器下次再运行时,它就会释放那些引用次数为0的值所占的内存。
“那么如何识别自己的内存有没有泄漏呢?”
“最常用的方式就是使用chrome浏览器查看内存占用情况。"
- 打开开发者工具,选择 Timeline 面板
- 在顶部的Capture字段里面勾选 Memory
- 点击左上角的录制按钮。
- 在页面上进行各种操作,模拟用户的使用情况。
- 一段时间后,点击对话框的 stop 按钮,面板上就会显示这段时间的内存占用情况。
如果内存占用基本平稳,接近水平,就说明不存在内存泄漏。反之,就是内存泄漏了。
注意事项:
虽然有垃圾回收机制但是我们编写代码操作不当还是会造成内存泄漏。
1. 意外的全局变量引起的内存泄漏。
原因:全局变量,不会被回收。
解决:使用严格模式避免。
2. 闭包引起的内存泄漏
原因:闭包可以维持函数内局部变量,使其得不到释放。
解决:将事件处理函数定义在外部,解除闭包,或者在定义事件处理函数的外部函数中,删除对dom的引用。
3. 没有清理的DOM元素引用
原因:虽然别的地方删除了,但是对象中还存在对dom的引用
解决:手动删除。
4. 被遗忘的定时器或者回调
原因:定时器中有dom的引用,即使dom删除了,但是定时器还在,所以内存中还是有这个dom。
解决:手动删除定时器和dom。
5. 子元素存在引用引起的内存泄漏
原因:div中的ul li 得到这个div,会间接引用某个得到的li,那么此时因为div间接引用li,即使li被清空,也还是在内存中,并且只要li不被删除,他的父元素都不会被删除。
解决:手动删除清空
概况总结:
内存泄漏:不再用到的内存没有释放
垃圾回收机制:当该资源的引用数为0,则释放
猜你喜欢
- 2025-06-23 JavaScript 开发者常犯的 10 个典型错误
- 2025-06-23 这7道问题可以检验你掌握Javascript的真正实力
- 2025-06-23 HarmonyOS NEXT 如何有效地进行内存管理和避免内存泄露?
- 2025-06-23 JS 函数柯里化(js函数柯里化面试题)
- 2025-06-23 《深入理解javascript原型和闭包系列》 知识点整理
- 2025-06-23 JS面试题突破:什么是闭包?(闭包 js)
- 2025-06-23 JavaScript闭包(javascript 闭包)
- 2025-06-23 “闭包到底是什么?90% 的前端开发者都没真正搞懂!”
- 2024-10-04 两个小案例让你深入理解 Javascript 闭包和作用域
- 2024-10-04 js中的闭包 js闭包的使用
你 发表评论:
欢迎- 560℃Oracle分析函数之Lag和Lead()使用
- 556℃几个Oracle空值处理函数 oracle处理null值的函数
- 546℃Oracle数据库的单、多行函数 oracle执行多个sql语句
- 542℃0497-如何将Kerberos的CDH6.1从Oracle JDK 1.8迁移至OpenJDK 1.8
- 539℃Oracle 12c PDB迁移(一) oracle迁移到oceanbase
- 531℃【数据统计分析】详解Oracle分组函数之CUBE
- 519℃最佳实践 | 提效 47 倍,制造业生产 Oracle 迁移替换
- 509℃Oracle有哪些常见的函数? oracle中常用的函数
- 最近发表
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端react (48)
- 前端aes加密 (58)
- 前端脚手架 (56)
- 前端md5加密 (54)
- 前端富文本编辑器 (47)
- 前端路由 (61)
- 前端数组 (73)
- 前端排序 (47)
- 前端密码加密 (47)
- Oracle RAC (73)
- oracle恢复 (76)
- oracle 删除表 (48)
- oracle 用户名 (74)
- oracle 工具 (55)
- oracle 内存 (50)
- oracle 导出表 (57)
- oracle 中文 (51)
- oracle的函数 (57)
- 前端调试 (52)
- 前端登录页面 (48)
本文暂时没有评论,来添加一个吧(●'◡'●)