Pořadí vlastností je v objektech JavaScript předvídatelné od ES2015

Dnešní učení mě překvapilo!

Četl jsem Twitter a narazil jsem na vlákno, které založil Sebastian McKenzie. V tomto vlákně sdílel úryvek React, který by se spoléhal na pořadí konkrétních vlastností v objektu.

styles({
  backgroundBlue: true,
  backgroundRed: true
});

Ve úryvku nad pozadím by bylo červené jako „zobrazuje se jako poslední“. Pokud chvíli děláte JavaScript, možná vás hned napadne – Počkejte, co !?!

V tomto příspěvku sdílím hlavně úryvky a fakta, protože nechci opakovat obsah zdrojů uvedených na konci.

Obvyklá mylná představa – „pořadí vlastností JavaScriptu nelze zaručeno"

Když jste před několika lety začali psát JavaScript, možná jste slyšeli tvrzení, že pořadí vlastností v objektech JS není předvídatelné. Nikdy jsem se nesetkal s podivným a neobvyklým pořadím vlastností, ale vždy jsem se řídil pravidlem „nikdy se nespoléhejte na pořadí vlastností“.

Interní ownPropertyKeys metoda

Ukazuje se, že od ES2015 existují metody, které jsou založeny na konkrétních pravidlech definujících pořadí vlastností a kromě jednoho konkrétního případu je pořadí chronologické. Pořadí vlastností v objektu závisí na typu zahrnutých vlastností a jejich hodnotách.

Při pohledu na specifikaci jsou pravidla definována v interní metodě „ownPropertyKeys“. Což je například používáno poměrně novými metodami Object.getOwnPropertyNames a Reflect.ownKeys .

Zajímavé je, že došlo ke změně specifikace např. Object.keys z ES5 na ES6. Specifikace ES6 definuje Object.keys také spoléhá na ownPropertyKeys díky čemuž je předvídatelný i v dnešních prohlížečích.

To také znamená, že s touto metodou musíte být opatrní a neměli byste se spoléhat na předvídatelné pořadí pomocí Object.keys protože výsledky se mohou lišit v závislosti na implementaci prohlížeče.

Ale dost teorie:pojďme se podívat na definované pořadí vlastností pro metody implementující ownPropertyKeys .

1. Celočíselné indexy

Všechny vlastnosti, které jsou celočíselnými indexy, se objeví jako první v celkovém pořadí vlastností objektu a jsou seřazeny podle čísel.

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

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

2. Řetězce (které nejsou celá čísla)

Vlastnosti, které se nepočítají do celočíselných indexů a nejsou typu Symbol dále a postupujte chronologicky.

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. Symboly

Konečně i symboly sledují chronologické pořadí.

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

Pořadí kombinovaných vlastností objektu

Když tato pravidla zkombinujete, uvidíte, že celá čísla jsou vždy v „první řadě“ vlastností objektu, za nimiž následují řetězce a symboly. Navíc můžeme řídit pořadí vlastností řetězce a symbolu, protože jsou chronologické!

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

Upraveno:Jak upozornila Malgosia Stepniak, "vlastní majetkový řád" je plně podporován pouze v moderních prohlížečích a ne např. IE.

Další zdroje

Díky Axelovi, který o tom psal již před třemi lety. :)

  • Pořadí procházení vlastností objektů v ES6 od Axela Rauschmayera
  • Specifikace jazyka ECMAScript® 2019 – OrdinaryOwnPropertyKeys
  • "Zavádí ES6 dobře definované pořadí výčtu pro vlastnosti objektů?" na Stack Overflow