一行代码解决数组长度检查慢的问题
在 JavaScript 性能优化的江湖里,一直流传着一个经典且历久弥新的技巧 —— 在编写 for 循环时,提前缓存数组的 length 属性。
这个技巧的核心逻辑其实很简单:当我们用 for 循环遍历数组时,如果每次循环都通过array.length
获取数组长度,JavaScript 引擎就需要重复计算这个值。尤其当数组规模较大、循环次数频繁时,这种重复计算会像水滴石穿般累积成性能损耗。
你一定见过这样的代码:
// “优化”前的代码 for (let i = 0; i < someArray.length; i++) { // ... do something } // “优化”后的代码 for (let i = 0, len = someArray.length; i < len; i++) { // ... do something }
这个建议的逻辑很简单:每次循环都去访问 someArray.length
会产生额外的开销,不如用一个局部变量 len
把它存起来,这样可以提高循环性能。
那么,length
检查真的很慢吗?
对于标准数组,length 快得惊人
在现代 JavaScript 引擎中,访问 .length
的速度几乎是恒定的,因为它只是一个简单的属性读取,引擎内部直接存储了这个值。
所以,对于标准数组,以下代码在性能上几乎没有区别,但后者明显更简洁、更易读,也更符合现代 JavaScript 的编码风格:
// 老旧的、手动优化的方式(不推荐) const arr=[1, 2, 3]; for(let i = 0, len = arr.length; i < len; i++) { console.log(arr[i]); } // 现代、简洁的方式(推荐) const arr=[1, 2, 3]; for(const item of arr) { console.log(item); } //或者 arr.forEach(item => { console.log(item); });
对于 DOM 集合的 length
既然普通数组的 length
很快,那这个流传已久的优化技巧到底是从何而来的呢?
答案指向了浏览器环境中的一个特殊对象:DOM 集合,尤其是 NodeList
和 HTMLCollection
。
当我们使用 document.getElementsByTagName()
或 element.childNodes
这样的方法时,得到的不是一个真正的 JavaScript Array
,而是一个实时的集合。
每当我们访问它的 length
属性时,浏览器必须重新去查询 DOM,计算符合条件的元素数量。
现在,想象一下这个可怕的场景:
const divs = document.getElementsByTagName('div'); // 这是一个实时的 HTMLCollection // 每次循环,浏览器都会重新去 DOM 树里数一遍有多少个 div for (let i = 0; i < divs.length; i++) { // 假设我们在这里创建并插入一个新的 div const newDiv = document.createElement('div'); document.body.appendChild(newDiv); }
在这个例子中,每次循环都会发生:
i < divs.length
:浏览器重新查询 DOM,计算divs.length
- 循环体执行,一个新的 <div> 被添加到
document.body
中 - 下一次循环,
divs.length
的值变大了
这不仅会导致无限循环,还会在每次循环条件判断时,触发一次昂贵的 DOM 重查询。
正确姿势
现在我们知道了问题的根源。那么,正确的做法是什么?
将 DOM 集合转换为真正的数组
在对 DOM 集合进行复杂操作之前,先把它变成一个静态的、真正的 JavaScript 数组。既可避免 length
性能陷阱,还能使用所有数组方法(map
, filter
, 等)。
// 推荐!使用 Array.from() const divs = Array.from(document.getElementsByTagName('div')); // 或者使用展开语法 const divs = [...document.getElementsByTagName('div')]; // 现在 divs 是一个真正的数组了,可以安全、高效地遍历 divs.forEach(div => { // ... }); for (let i = 0; i < divs.length; i++) { // 这里的 .length 访问非常快! }
现代浏览器中,querySelectorAll()
返回的是静态的 NodeList
,其 length
不会动态变化。但 getElementsByTagName
等仍然返回实时集合。为了统一和安全,将所有 DOM 集合在使用前转换为数组是一个好习惯。
对于普通 Array
对象,不需要再手动缓存 length
,优先选择 for...of
或高阶函数(如 forEach
, map
)来提升代码可读性;对于 DOM,先转数组。
以上关于一行代码解决数组长度检查慢的问题的文章就介绍到这了,更多相关内容请搜索码云笔记以前的文章或继续浏览下面的相关文章,希望大家以后多多支持码云笔记。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 admin@mybj123.com 进行投诉反馈,一经查实,立即处理!
码云笔记 » 一行代码解决数组长度检查慢的问题