JavaScript 对象遍历顺序并非完全随机,而是遵循严格的规范。正整数键按数值大小排序,其余字符串和 Symbol 键按插入顺序排列。本文详细解析 Object.keys、Object.entries 等方法的遍历行为,重点说明 for...in 在 ES2019 后遵循相同规则但会遍历原型链,并建议在需要严格顺序时使用 Map。
JavaScript 对象遍历顺序概述
常有人提及 JavaScript 中对象遍历顺序不固定,这一观点并不完全准确。
常用遍历方法
对象内部存在既定的遍历规则,该规则受元素插入顺序影响,但并非完全由插入顺序决定。若业务场景严格要求遍历顺序与插入顺序一致,推荐使用 Map 数据结构。 常见的对象遍历方式包括:
- Object.keys
- Object.entries
- Object.getOwnPropertyNames
- Reflect.ownKeys
- ......
正整数键与非整数键的排序规则
上述方法均遵循相同的遍历规则,具体表现取决于键(key)的数据类型。 若对象的键为形如 '1' 或 '200' 的正整数字符串,遍历顺序将依据键值的大小进行排序。 示例如下:
const obj = {}
obj['10'] = 'a';
obj['9'] = 'b';
obj[8] = 'c';
obj[7] = 'd';
console.log(Object.keys(obj)) // ["7", "8", "9", "10"]
最终遍历结果完全无视插入顺序。值得注意的是,即使添加属性时使用的是 Number 类型索引,最终键名也会被隐式转换为字符串。
数组作为对象的一种特殊形式,同样适用此规则。此外,具有 length 属性且键为正整数的类数组对象,其遍历顺序也遵循索引顺序。 若键值无法转换为正整数(包括负数字符串如 '-1'、小数字符串如 '1.0' 及其他普通字符串),则遍历顺序符合直觉,即按照插入对象的先后顺序进行:
const obj2 = {}
obj2['1.1'] = 'a';
obj2['1.0'] = 'b';
obj2['-1'] = 'c';
obj2['jack'] = 'd'
console.log(Object.keys(obj2)); // ["1.1", "1.0", "-1", "jack"]
Symbol 类型与混合键的遍历优先级
对象的键值类型除字符串外,还可包含 Symbol 类型。Symbol 类型的键同样严格遵循插入顺序进行遍历。
若对象同时包含上述所有类型的键(各类字符串及 Symbol),其遍历顺序遵循以下优先级:
- 首先,按照正整数规则遍历所有正整数键。
- 其次,按照插入顺序遍历剩余的字符串键。
- 最后,按照插入顺序遍历所有 Symbol 类型的键。
for...in 的特殊行为与 ES2019 规范
至此,对象的基本遍历顺序已清晰。需额外注意的是 for...in 语句的遍历行为。
早期浏览器对 for...in 的顺序并无统一标准,由厂商自行决定。若需兼容旧版浏览器且对顺序有严格要求,建议避免使用。ES2019 提案已规范此行为,使 for...in 遵循上述对象遍历规则。
尽管遵循上述规则,for...in 还会遍历原型链上的属性。其变量元素的规则为:先按对象遍历规则遍历对象自身的键,随后按相同规则遍历原型链上的键,直至原型链顶端。
除 for...in 的上述特性外,对象遍历顺序的核心内容即为此。
关于 JavaScript 对象遍历顺序的详解至此结束。如需了解更多相关内容,可搜索本站往期文章或继续浏览后续文章,感谢支持。