JavaScript数组动态特性与遍历机制详解
本文详细解析JavaScript数组的动态特性,包括无需预定义大小、通过length属性自动扩容及手动截断机制。探讨数组中“空槽”对length值的影响,对比不同遍历方式(如for...in与for)在性能与结果上的差异,并辨析数组删除元素后的空洞问题及数组与对象的适用场景。
JavaScript数组动态特性与遍历机制详解
前文已介绍数组索引,本节将重点讨论数组的具体使用方式。
数组的大小与动态调整
数组的大小
JavaScript中的数组支持动态调整大小,严格来说,它不存在传统意义上的数组越界概念。例如,表达式 a[a.length] 是合法的。假设声明数组 a = [1, 3, 5],其当前长度为3,最后一个元素的索引为2。此时访问 a[3] 会返回 undefined,而执行赋值 a[3] = 7 则相当于向数组 a 添加了一个新元素,使其长度变为4。读者可将相关代码在浏览器中运行验证。
var a = [];
for(int i = 0; i <= a.length; i++)
{
a[a.length] = i;
}
在我的电脑上,火狐会立马崩掉,chrome这一个标签cpu占用99%(使用chrome的任务管理器查看的)。
JavaScript中数组的 length 属性值会随元素增减自动更新。此外,开发者也可以手动设置 length 属性:若设置为更大的值,不会为数组分配额外空间;若设置为更小的值,则会删除所有下标大于或等于新 length 值的属性。
关于数组 length 值的来源,部分资料指出其等于最大数字索引值加一,这大致正确。但若将空槽(empty slots)计算在内,length 值即代表数组的元素总数。参见下图说明:

从图中可见,数组 a 中 a[0] 和 a[10] 已赋值,此时 a 的 length 为11,中间存在9个 empty slot(暂译为“空槽”)。这九个空槽是否计入 length?笔者认为应当计入,这样能合理解释 length 的值。这些空槽的值为 undefined!因此,在 Chrome 中使用 foreach 遍历(for...in)时,这些空槽会被跳过;而使用 for 循环遍历则会打印出 undefined。Firefox 的表现可能不同,建议自行测试。
数组的遍历与性能分析
数组的遍历
昨日浏览微博转发的 JS 教程时,文中提到遍历数组时判断条件 i < a.length 会导致每次循环都重新计算长度,从而对性能产生轻微影响。对此我持保留态度,不确定该说法是否准确,且不同浏览器可能存在不同的优化策略。我在网上搜索发现,许多网页建议缓存数组大小,但多为相互转载,缺乏主见且未阐明原理,因此我对此表示怀疑。我在 Chrome 中测试后,未发现明显的性能差异。关键在于,length 是数组的一个属性,每次调用 a.length 仅是访问该属性,而属性通常以哈希方式存储,因此访问的时间复杂度为 O(1)。这是我的观点,如有误请指正。
关于数组的 foreach 遍历,JavaScript 的方式相对于 Java/C# 等语言显得较为特殊:
for(var name in ['huey', 'dewey', 'louie']) {
console.log(name);
}
/*
打印结果:
0
1
2
*/
可以看到,打印的结果不是数组的元素,而是数字索引值(感觉这好像也可以说明,js的数组也是用hash的方式存储的),不管怎样,这一点要注意。(至于为什么这样,我觉得数组元素都是数组的属性,这个遍历是遍历的length值,从0到length。而不是逐个输出数组的元素,因为元素是属性,数组又不只数字索引这一种属性,那么为什么这样遍历的时候只输出它们呢,而不是length,push,join等方法?公平起见,只好输出数组的数字索引了。当然,这只是我自己的看法,具体怎么样我没研究。)
数组常用方法及对象辨析
数组的一些方法
数组提供了 push 和 pop 方法,使数组具备堆栈特性。对数组使用 delete 可以移除某个元素,但这会在数组中留下一个空洞(即 delete 仅删除该位置的值,不改变数组大小,原位置类型变为 undefined)。这是因为排在被删除元素之后的元素保留着它们最初的属性,因此应使用 splice 对经过 delete 操作的数组进行“瘦身”,它会移除被删除的属性,但效率并非最高。此外,数组还包含 map、reduce、filter 等方法,此处不再赘述(这些方法与 Python 中的 list 类似)。
补充
最后补充一点,前文曾提及,JavaScript 中的数组本质上是对象(这显而易见)。那么,数组和对象是否可以互换使用?答案是肯定的。不过为了代码清晰,建议分开使用。下文将讨论何时使用数组,何时使用对象(参考《JavaScript语言精粹》):
当属性名是小而连续的整数时,应该使用数组,否则,使用对象。 另外由于js中对数组和对象使用 typeof 的结果都是 Object,因此判断一个对象是否为数组的方法:
var is_array = function(value) {
return Object.prototype.toString.apply(value) === '[object Array]';
};
番外
觉得闭包被神化了,可能语言层面上的实现有技术,但是在应用层面我觉得就应该那样啊,使用的时候都感觉不到那是在用闭包。但是这个闭包却几乎成了面试前端必问的概念了。
以上所述就是本文的全部内容了,希望大家能够喜欢。
什么时候该用JS构造器:与工厂模式、字面量的选择对比
2026-11-05 16:18:22
推荐几款轻量级JS照片墙开源库及对比
2026-11-05 15:56:19
JavaScript递归写法有哪些常见陷阱及避免方法
2026-11-05 14:53:38
JS数组浅拷贝与深拷贝怎么选?场景与方法总结
2026-11-05 14:41:02
p5.js 中 setup() 和 draw() 函数的执行机制详解
2026-11-05 12:32:38
