Retour à la liste des articles

Objets JavaScript : Pourquoi l'ordre d'insertion des propriétés est-il préservé ?

Publié le : 2 juin 2025

5 min de lecture

Objets JavaScript : Pourquoi l'ordre d'insertion des propriétés est-il préservé ?
javascript es6 objects

Tu t’es peut-être déjà demandé pourquoi les clés d’un objet JavaScript apparaissent souvent dans l’ordre où tu les as définies, que tu utilises Object.keys() ou que tu le parcours ?

const user = {
  name: 'Alice',
  age: 30,
  email: 'alice@example.com',
};

console.log(Object.keys(user));
// ["name", "age", "email"] - toujours dans cet ordre !

Ce comportement, bien que pratique, n’a pas toujours été la norme. Explorons ensemble pourquoi et comment l’ordre des propriétés est géré en JavaScript moderne.

Le « Pourquoi » : Une Question de Prévisibilité

La raison principale de cette standardisation est le déterminisme. Selon le Dr. Axel Rauschmayer dans “Exploring JS” :

En principe, les objets ne sont pas ordonnés. La raison principale pour ordonner les propriétés est que les opérations qui listent les entrées, les clés ou les valeurs soient déterministes. Cela aide, par exemple, pour les tests.

Pourquoi c’est important ?

Imagine que tu testes une fonction qui transforme un objet en chaîne de caractères :

function objectToString(obj) {
  return Object.keys(obj)
    .map((key) => `${key}: ${obj[key]}`)
    .join(', ');
}

const config = { port: 3000, host: 'localhost', ssl: true };
console.log(objectToString(config));
// Résultat prévisible : "port: 3000, host: localhost, ssl: true"

Sans ordre garanti, tes tests pourraient échouer de manière aléatoire selon l’environnement d’exécution !

Les Règles de l’Ordre (depuis ES2015)

Avant ECMAScript 2015, la spécification ne garantissait pas l’ordre d’énumération des propriétés. Depuis ES2015, l’ordre est strictement défini selon ces règles :

1. Clés numériques (Integer-indexed keys)

Les clés qui sont des chaînes représentant des entiers sont listées en premier, triées numériquement :

const obj = {
  10: 'dix',
  2: 'deux',
  1: 'un',
};

console.log(Object.keys(obj));
// ["1", "2", "10"] - triées numériquement, pas alphabétiquement !

⚠️ Attention : "10" vient après "2" car c’est un tri numérique, pas alphabétique !

2. Autres clés chaînes (String keys)

Les autres clés de type chaîne suivent leur ordre d’insertion :

const person = {};
person.name = 'Bob';
person.age = 25;
person.city = 'Paris';

console.log(Object.keys(person));
// ["name", "age", "city"] - ordre d'insertion préservé

3. Clés symboles (Symbol keys)

Les clés de type Symbol viennent en dernier, également dans leur ordre d’insertion :

const sym1 = Symbol('premier');
const sym2 = Symbol('second');

const obj = {
  b: 'chaîne',
  [sym2]: 'symbole 2',
  a: 'autre chaîne',
  [sym1]: 'symbole 1',
};

console.log(Reflect.ownKeys(obj));
// ['b', 'a', Symbol(second), Symbol(premier)]
//  ^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//  chaînes Puis symboles (par ordre d'insertion)

Exemple Complet : Tous les Types Mélangés

const complexObject = {
  beta: 'deuxième propriété',
  100: 'cent',
  alpha: 'première propriété',
  5: 'cinq',
  gamma: 'troisième propriété',
};

// Ajout de symboles
const sym1 = Symbol('symbol1');
const sym2 = Symbol('symbol2');
complexObject[sym1] = 'valeur symbole 1';
complexObject[sym2] = 'valeur symbole 2';

// Ajout d'une autre propriété chaîne
complexObject.delta = 'quatrième propriété';

console.log(Reflect.ownKeys(complexObject));
// Résultat :
// [
//   '5', '100',                        👉🏽 // 1. Entiers triés numériquement
//   'beta', 'alpha', 'gamma', 'delta', 👉🏽 // 2. Chaînes par ordre d'insertion
//   Symbol(symbol1), Symbol(symbol2)   👉🏽 // 3. Symboles par ordre d'insertion
// ]

Méthodes d’Énumération : Qui Respecte Quoi ?

MéthodeClés numériquesClés chaînesSymbolesPropriétés héritées
Object.keys()✅ Oui✅ Oui❌ Non❌ Non
Object.getOwnPropertyNames()✅ Oui✅ Oui (même non-énumérables)❌ Non❌ Non
Object.getOwnPropertySymbols()❌ Non❌ Non✅ Oui❌ Non
Reflect.ownKeys()✅ Oui✅ Oui✅ Oui❌ Non
for...in✅ Oui✅ Oui❌ Non✅ Oui

Exemple pratique avec différentes méthodes :

const obj = {
  name: 'Test',
  10: 'dix',
  age: 30,
  2: 'deux',
};
obj[Symbol('test')] = 'symbole';

console.log('Object.keys():', Object.keys(obj));
// ['2', '10', 'name', 'age']

console.log('Reflect.ownKeys():', Reflect.ownKeys(obj));
// ['2', '10', 'name', 'age', Symbol(test)]

// for...in (avec vérification des propriétés propres)
const keys = [];
for (let key in obj) {
  if (Object.hasOwn(obj, key)) {
    keys.push(key);
  }
}
console.log('for...in:', keys);
// ['2', '10', 'name', 'age']

Cas Particuliers et Pièges

Piège n°1 : Les chaînes qui ressemblent à des nombres

const tricky = {
  '02': 'zéro-deux',
  2: 'deux',
  10: 'dix',
};

console.log(Object.keys(tricky));
// ['2', '10', '02']
// "02" n'est PAS un entier canonique, donc vient après !

Piège n°2 : Modification vs création

const obj = { b: 1, a: 2 };
obj.b = 99; // Modification - l'ordre ne change pas !

console.log(Object.keys(obj));
// ['b', 'a'] - l'ordre original est préservé

delete obj.b;
obj.b = 1; // Recréation - va à la fin !

console.log(Object.keys(obj));
// ['a', 'b'] - 'b' est maintenant à la fin

Avant ES2015 : Le Chaos

Avant 2015, seul l’ordre des clés numériques était généralement respecté. Pour les autres clés :

  • Chrome (V8) : Respectait souvent l’ordre d’insertion
  • Firefox (SpiderMonkey) : Pouvait réorganiser les propriétés
  • Internet Explorer : Comportement imprévisible

Cette incohérence rendait le développement cross-browser plus complexe !

Conseils Pratiques

✅ À faire :

  • Utilise Object.keys() pour itérer sur les propriétés énumérables
  • Utilise Reflect.ownKeys() quand tu as besoin de TOUTES les propriétés (y compris symboles)
  • Compte sur l’ordre défini par la spécification pour tes tests

❌ À éviter :

  • Te fier à l’ordre dans du code critique sans comprendre les règles
  • Supposer que l’ordre sera le même dans des environnements très anciens
  • Utiliser for...in sans Object.hasOwn() si tu ne veux que les propriétés propres

Conclusion

Depuis ES2015, JavaScript garantit un ordre spécifique et prévisible pour les propriétés d’objets :

  1. Entiers triés numériquement
  2. Chaînes par ordre d’insertion
  3. Symboles par ordre d’insertion

Cette standardisation améliore grandement la prévisibilité du code et facilite l’écriture de tests fiables. Comprendre ces règles te permet d’éviter les pièges et d’écrire du JavaScript plus robuste.

Je te recommande aussi :