下面这段React的代码,最终渲染的效果依赖于对象中属性的顺序。
但从执行效果来看,背景将显示为红色,因为它是“放在最后的属性”。
如果你已经用了一段时间的JavaScript,你可能会立刻想到 - 等等,什么!?属性是有顺序的吗?
常见的误解 - “JavaScript中无法保证属性的顺序”
几年前写JavaScript时,您可能听到过JS对象中的属性顺序是不可预测的说法。
虽然我还没遇到过一些对顺序有强制要求的需求,但我始终遵循“从不依赖属性顺序”的规则。
内部方法ownPropertyKeys
实际上,从ES2015以来,就已经有一些包含属性顺序规则的方法了,这得益于内部方法ownPropertyKeys
的实现。
对象中属性的顺序取决于所包含属性的类型及其值。具体的顺序规则可以查看定义在“内部方法ownPropertyKeys”中的准则。有些新的方法已经在使用这种规则,例如Object.getOwnPropertyNames
和Reflect.ownKeys
。
规则如下:
有趣的是,一些方法的规格在变化,例如Object.keys
从ES5到ES6的变化。ES6规范定义了Object.keys
也依赖于ownPropertyKeys
,这使得属性顺序在支持ES6的浏览器中可预测。
但这也意味着您必须小心使用此方法,并且不应该强依赖于它来对属性顺序的预测,因为Object.keys
可能会因浏览器实现的差异导致结果不同。
原理讲的差不多了,现在让我们来看看代码。
整数
以整数索引为key的所有属性,首先出现在整个对象属性顺序中,并之间以数字方式排序。
‘1’是整数索引,而’01’不是。你可以这样理解,对一个数组 const a=[1,2,3], a[‘0’]===a[0],值是1,但a[‘01’]值是undefined。
字符串(不是整数)
key不计入整数索引且不是Symbol
类型的属性,是第二顺序,且它们间按照时间顺序排列。
Symbols
最后是Symbols,之间也遵循时间顺序。
组合规则
组合这些规则时,您将看到整数始终位于对象属性的“前排”,后跟字符串和Symbols。此外,我们可以控制字符串和Symbols属性的顺序,因为它们是按时间顺序排列的!
但是,正如这篇文章指出的,“自有属性顺序”规则仅在一些现代浏览器中得到完全支持,而其他则不行,比如IE不支持。
资源
- 原文: https://www.stefanjudis.com/today-i-learned/property-order-is-predictable-in-javascript-objects-since-es2015/
- The traversal order of object properties in ES6
- ECMAScript® 2019 Language Specification - OrdinaryOwnPropertyKeys
- “Does ES6 introduce a well-defined order of enumeration for object properties?” on Stack Overflow