在JavaScript中,数组并不是一种完全独立的基础类型,它的本质其实是对象。这就解释了为什么我们可以在数组上添加非数字键,而这些键的表现又和真正的数字索引有所不同。理解这一点,对于处理复杂数据结构非常重要。

数组也是对象
JavaScript的数组由内置的Array构造函数创建,其原型链指向Array.prototype,而Array.prototype本身又继承自Object.prototype。因此,数组天然具备对象的全部能力,包括以字符串作为键来保存属性。
// 创建一个普通数组 let arr = [10, 20, 30]; // 添加非数字键 arr.name = 'myArray'; arr['info'] = 'test'; console.log(arr.name); // 输出 myArray console.log(arr.length); // 输出 3,非数字键不影响length
非数字键与数字索引的区别
只有非负整数字符串(如"0"、"1")才会被数组当作索引处理,并影响length与迭代行为。其他字符串键仅仅是数组对象的普通属性。
| 键类型 | 是否影响length | 是否被for循环以索引遍历 |
|---|---|---|
| 数字索引(0,1,2) | 是 | 是 |
| 非数字键(name, info) | 否 | 否 |
遍历时的差异
使用for循环基于length遍历,只会访问数字索引;而for...in会枚举所有可枚举属性,包括非数字键,这通常不是处理数组所期望的。
let list = [1, 2];
list.tag = 'demo';
for (let i = 0; i < list.length; i++) {
console.log(list[i]); // 只输出 1 和 2
}
for (let key in list) {
console.log(key); // 输出 0, 1, tag
}
对象中的非数字键处理
普通对象使用非数字键是常态。无论是字符串、符号还是其他形式,都作为自身属性存储。我们可以通过Object.keys获取可枚举键,用Reflect或delete操作管理属性。
let obj = {};
obj['first-name'] = 'Tom';
obj[100] = 'num'; // 数字也会被转为字符串键
console.log(Object.keys(obj)); // 输出 ["first-name", "100"]
delete obj['first-name'];
console.log('first-name' in obj); // 输出 false
使用Symbol作为键
Symbol类型的键不会出现在Object.keys结果中,常用于元编程或隐藏属性,数组同样支持。
const sym = Symbol('desc');
let data = [1];
data[sym] = 'hidden';
console.log(Object.keys(data)); // 输出 ["0"]
console.log(data[sym]); // 输出 hidden
序列化时的注意点
JSON序列化只处理可枚举的自有属性,且数字索引和非数字键都会被转为JSON对象的字段,但数组的length概念在JSON中消失。
let a = [1, 2];
a.meta = 'x';
console.log(JSON.stringify(a)); // 输出 {"0":1,"1":2,"meta":"x"}
开发建议
- 避免在数组上随意挂载非数字键,以免混淆数据结构语义。
- 遍历数组优先使用for、forEach、for...of,而非for...in。
- 若需关联元数据,可考虑用对象包裹数组,或使用Map结构。
记住:数组是对象的一个特殊分支,非数字键只是对象属性的自然延伸,而非数组特性。
JavaScript数组非数字键对象属性修改时间:2026-07-27 17:03:25