对象属性遍历顺序:数字键按数值升序优先,其余键按插入顺序,Symbol键排最后且按插入序;现代引擎一致,但关键逻辑应使用Map或数组替代。

JavaScript中对象属性的遍历顺序并不是完全由规范强制规定的,因此在不同引擎(如V8、SpiderMonkey、JavaScriptCore)中存在细节差异,尤其体现在数字键、字符串键、Symbol键的处理上。理解这些差异对编写可预测的代码(比如序列化、调试输出、依赖顺序的逻辑)很重要。
数字键优先且按数值升序排列
ES2015(ES6)起,规范明确要求:对象中所有以整数形式表示的字符串键(即能被转换为有效无符号32位整数的字符串,如 "0"、"42"、"999999999"),必须在遍历中排在最前面,并按数值大小升序排列,而非字典序或插入顺序。
-
{"10": "a", "2": "b", "1": "c"}遍历时顺序是"1"→"2"→"10"(不是"10"→"1"→"2") - 注意:
"-1"、"1.5"、"01"不被视为整数键,归入普通字符串键 - V8(Chrome/Node.js)、SpiderMonkey(Firefox)、JavaScriptCore(Safari)均严格遵守该规则
其余键按插入顺序保留(但有例外)
非整数字符串键(如 "name"、"_id"、"01")和 Symbol 键,在规范中规定应保持插入顺序。主流引擎目前都实现了这一点,但需注意以下边界情况:
- 通过
Object.defineProperty添加的不可枚举属性,不影响枚举顺序,但若后续用obj.key = value赋值,仍按新插入时间排序 - 使用
Object.assign({}, obj)或展开语法{...obj}会重建属性顺序,遵循源对象的遍历顺序(即继承上述数字键+插入序规则) - 某些极旧版本引擎(如 IE10 及更早)不保证字符串键顺序,但现代环境已无需兼容
Symbol 键总是排在最后,且按插入顺序
根据规范,所有 Symbol 类型的键必须出现在所有字符串键之后,并彼此之间维持插入顺序:
立即学习“Java免费学习笔记(深入)”;
const s1 = Symbol('a'); const s2 = Symbol('b'); const obj = {z: 1, [s2]: 2, a: 3, [s1]: 4};- 遍历结果顺序为:
"z"→"a"→s1→s2(数字键若有则更靠前) - 所有现代引擎(V8、SpiderMonkey、JavaScriptCore)一致实现此行为,无差异
实际开发建议:别依赖对象属性顺序做关键逻辑
尽管当前引擎行为高度一致,但对象本质不是有序结构。若业务逻辑强依赖顺序(如配置项执行、字段校验顺序、UI渲染顺序),更稳妥的方式是:
- 改用
Map—— 它明确保证插入顺序,且支持任意键类型 - 用数组 + 对象组合,例如
[{key: 'name', value: 'Alice'}, {key: 'age', value: 30}] - 需要序列化时,显式排序:
Object.keys(obj).sort().forEach(...)或按自定义规则Object.entries(obj).sort(...) - 调试或日志输出时,可用
JSON.stringify(它本身也遵循规范顺序),但注意会忽略Symbol和函数










