在ES6中对象属性的顺序是可预测的

常见的误解–“无法保证JavaScript属性的顺序”:几年前开始编写JavaScript时,您可能已经听说过JS对象中属性的顺序是不可预测的。我从来没有碰到过奇怪和不寻常的属性顺序,但是我始终遵循从不依赖属性顺序的原则。

内部ownPropertyKeys方法

事实上,自ES6起,有一些方法基于定义属性顺序的特定规则,除了一种特殊情况外,该顺序是按时间顺序排列的,并依赖于对象属性的类型和值。

这些规则被定义在 规范中。例如,es6中新的函数Object.getOwnPropertyNames和Reflect.ownKeys已经使用了这些规则。

这个规则引起了一些有趣的变化,例如Object.keys从到的规则发生了变化。ES6规范规定Object.keys也依赖于ownPropertyKeys,这样就使得Object.keys在现代浏览器中的执行结果也是可预测。

但是,这也意味着您必须谨慎使用此方法,并且不应依赖于可预测的顺序使用Object.keys,因为Object.keys的执行结果。

但是已经有足够多的理由,让我们去了解ownPropertyKeys是如何定义的属性顺序的。

1.整数指数

所有为整数索引的属性均按整体对象属性顺序显示在第一位,并按数字升序排列。

const objWithIndices = {
          
   
  23: 23,
  1: 1,
  1000: 1000
};

console.log(Reflect.ownKeys(objWithIndices));
// [1, 23, 1000]
// ☝️ following numeric order

2.字符串(不是整数)

属性既不是整数索引,也不是Symbol类型的,按照添加的时间顺序排列。

const objWithStrings = {
          
   
  bar: bar,
  01: 01
};

objWithStrings.last = last;
objWithStrings[veryLast] = veryLast;

console.log(Reflect.ownKeys(objWithStrings));
// [bar, 01, last, veryLast]
// ☝️ following chronological order

3.Symbol

最后,Symbol也按照时间顺序排列。

const objWithSymbols = {
          
   
  [Symbol(first)]: first,
  [Symbol(second)]: second
};

objWithSymbols[Symbol(last)] = last;

console.log(Reflect.ownKeys(objWithSymbols));
// [Symbol(first), Symbol(second), Symbol(last)]
// ☝️ following chronological order

三种类型一起

将三种类型的属性放在一起时,整数始终位于对象属性的“第一行”中,其后是字符串和Symbol,此外,我们可以控制字符串和Symbol属性的顺序,因为它们是按添加的时间顺序排列!

const obj = {
          
   
  2: integer: 2,
  foo: string: foo,
  01: string: 01,
  1: integer: 1,
  [Symbol(first)]: symbol: first
};

obj[0] = 0;
obj[Symbol(last)] = symbol: last;
obj[veryLast] = string: very last;

console.log(Reflect.ownKeys(obj));
// [ "0", "1", "2", "foo", "01", "veryLast", Symbol(first), Symbol(last) ]
// -> 1. integers in numeric order
// -> 2. strings in chronological order
// -> 3. Symbols in chronological order

编辑:正如Malgosia Stepniak所指出的那样,仅现代浏览器完全支持 “own property order” ,而IE则不完全支持。

经验分享 程序员 微信小程序 职场和发展