ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

jstips 第 22 期:清空 JavaScript 数组的两种方式,从引用语义到内存泄漏

jstips 第 22 期:清空 JavaScript 数组的两种方式,从引用语义到内存泄漏 教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载本篇文章基于 JS Tips 开源仓库中的_posts/es_ES/javascript/2016-01-22-two-ways-to-empty-an-array.md及其多语言版本英文版、简体中文版、繁体中文版展开。当你在业务代码中需要清空一个数组时最常见的方式是重新赋值list []但这实际上只是把变量指向了一个新数组。本文要解决的核心问题是如何真正清空数组的底层内容、避免无谓的内存占用并理解两种写法对共享同一数组的其他引用产生的截然不同的影响。读完本文你将掌握list.length 0与list []的本质区别能在内存敏感或存在多引用的场景中做出正确选择并能准确预测含别名引用的数组清空代码的输出结果。两种清空数组的写法假设你定义了一个数组现在想清空它的内容。常规写法是重新赋值为一个新数组// 定义一个数组 var list [1, 2, 3, 4]; function empty() { // 清空数组 list []; } empty();但原文档指出还有一种效率更高的清空数组的方式——直接修改数组自身的length属性var list [1, 2, 3, 4]; function empty() { // 清空数组 list.length 0; } empty();两种写法执行后list的值都是[]但它们在底层做的事情完全不同后续产生的副作用也天差地别。本质区别换引用 vs 删内容这是本篇技巧的核心。原文档对两种方式给出了精炼的定性list []是换引用它把一个新的数组对象的引用赋值给变量list而其他任何指向旧数组的引用不受影响。旧数组的内容只要还被其他引用持有就会继续留在内存中这可能导致内存泄漏。list.length 0是删内容它把数组的length置为 0从而删除数组里的所有元素同时会影响到其他引用——所有指向这个数组的变量看到的都是同一个空数组。换句话说如果你有两个变量引用同一个数组a [1,2,3]; a2 a;使用list.length 0清空内容后a和a2这两个引用现在都指向同一个空数组。原文档特意提醒如果你不希望a2变成空数组就不要使用这种技术。这一行为与仓库中另一篇技巧 Know the passing mechanism第 44 期阐述的引用语义完全一致JavaScript 中对象数组也属于对象的引用值是按值传递的多个变量可以持有对同一底层对象的引用对对象内部状态的修改会透过所有引用被看到而对变量本身重新赋值则只影响该变量。list []属于改变变量指向list.length 0属于修改对象内部状态两者在引用模型中的层级完全不同。思考这段代码的输出原文档给出了一个经典的验证片段请先自己想一想输出是什么再看答案var foo [1,2,3]; var bar [1,2,3]; var foo2 foo; var bar2 bar; foo []; bar.length 0; console.log(foo, bar, foo2, bar2); // [] [] [1, 2, 3] []逐行推演foo和bar各自创建了一个独立的新数组[1, 2, 3]foo2 foo让foo2与foo指向同一个数组对象bar2 bar同理foo []只是让foo指向一个全新的空数组不触碰原数组内容因此foo2仍然持有完整的[1, 2, 3]bar.length 0直接清空了bar与bar2共同指向的那个数组所以bar和bar2都变成[]。最终输出[] [] [1, 2, 3] []foo和bar都是空数组但foo2保留原数据因为foo只是换了引用bar2被连带清空因为bar删除了共享数组的内容。这个例子把两种方式的差异表现得淋漓尽致。深入理解length 属性与内存释放length是数组对象的一个可写属性把它设置为0会触发数组元素的批量移除被移除的元素不再被数组引用因而在无其他引用的情况下可以被垃圾回收器回收。这正是list.length 0相较于重新赋值更受青睐的原因——它不产生旧数组内容仍被引用、滞留在内存中的问题。从源码结构看本仓库并未包含可运行的 JavaScript 实现或测试代码仓库以 Markdown 技巧文档为主见 README.md 的 Tips 列表因此上述内存回收结论属于 ECMAScript 规范层面的语言行为。需要说明的是原文档断言list.length 0更高效more performant这一结论本身没有附带基准数据我们可以把它理解为在需要清空并且该数组对象仍被多处引用时直接修改length避免了额外分配一个新数组对象的开销同时确保了所有引用方的一致性。若以严谨的工程态度对待建议在具体场景下用 性能测量技巧第 13 期提供的方法自行验证。其他常见的清空手段与适用场景除了上述两种方式日常代码中还有一些替代写法它们各自有明确的适用边界写法行为是否影响其他引用典型场景list []变量指向新数组旧数组留给其他引用否只想让当前变量丢弃这批数据list.length 0原地删除全部元素是所有引用同时变空想真正释放/复用当前数组对象list.splice(0, list.length)原地删除全部元素返回被删元素是需要拿到被删除元素的场景while (list.pop())或循环shift()逐个弹空原地删除是需要逐元素处理、副作用明显的场景性能较低值得提醒的是Array.prototype上还有大量与内容变换相关的方法Looping over arrays 第 79 期、3 Array Hacks 第 64 期对此有系统梳理但它们普遍是返回新数组而非原地清空使用时要注意区分。实战建议什么时候选哪一种综合原文档的结论与引用语义可以沉淀出以下选择准则当数组对象被多个变量/属性共享且你希望所有引用方都同时变空比如组件内部维护的一个列表被渲染逻辑和业务逻辑共同持有优先用list.length 0当你不希望其他引用受影响比如只想让当前变量换一批数据旧的交给别人或者数组会被彻底丢弃、随后整体重建用list []更合适在内存敏感的长生命周期应用中如果旧数组内容仍被其他引用持有重新赋值不会释放内存此时评估是否改用原地清空以帮助 GC 回收函数参数传数组时尤其要小心结合 Know the passing mechanism 的结论在函数内对参数执行arr.length 0会透传到调用方可能引发意想不到的副作用若只想在局部清空应显式创建新数组或先拷贝拷贝本身也有深浅之分见 Immutable structures and cloning 第 78 期。小结清空数组的两种方式在结果上都是数组变空但语义完全不同list []只是更换了变量的引用旧数组内容可能继续驻留内存并产生内存泄漏风险list.length 0则是原地删除全部元素会影响所有共享该数组的引用。本文的验证片段[] [] [1, 2, 3] []正是对这一差异的直观证明。下次清空数组时请先问自己一句这个数组对象还有别人在引用它吗答案将决定你选择哪一种写法。赞分享教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载相关推荐jstips 第 22 期清空 JavaScript 数组的两种方式——list [] 与 list.length 0 的引用语义、内存影响与选型指南jstips 第 22 期清空 JavaScript 数组的两种方式——list 与 list.length 0 的引用语义、内存影响与选型指南 本文教程jstips 第 38 期JavaScript 多维数组扁平化的五种实用方案jstips 第 38 期JavaScript 多维数组扁平化的五种实用方案 导读 本文基于 jstips 仓库第 38 号技巧 西班牙语原文 https:教程PaddleOCR EAST 文本检测算法全解析从论文原理到训练推理部署实战PaddleOCR EAST 文本检测算法全解析从论文原理到训练推理部署实战 导读 EASTEfficient and Accurate Scene Tex教程上一篇魔兽争霸3辅助WarcraftHelper地图大小解锁、宽屏适配与FPS解锁完整设置指南下一篇免费开源 Forza Mods AIO地平线4/5修改完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表