178 votes

trier les propriétés des objets et JSON.stringify

Mon application contient un grand nombre d'objets, que je mets en chaîne et que je sauvegarde sur le disque. Malheureusement, lorsque les objets du tableau sont manipulés, et parfois remplacés, les propriétés des objets sont listées dans des ordres différents (leur ordre de création ?). Lorsque je fais JSON.stringify() sur le tableau et que je l'enregistre, un diff montre que les propriétés sont listées dans des ordres différents, ce qui est gênant lorsque l'on essaie de fusionner les données avec des outils de diff et de fusion.

Idéalement, j'aimerais trier les propriétés des objets par ordre alphabétique avant d'effectuer le stringify, ou dans le cadre de l'opération de stringify. Il existe du code pour manipuler les objets du tableau à de nombreux endroits, et il serait difficile de le modifier pour toujours créer les propriétés dans un ordre explicite.

Les suggestions sont les bienvenues !

Un exemple condensé :

obj = {}; obj.name="X"; obj.os="linux";
JSON.stringify(obj);
obj = {}; obj.os="linux"; obj.name="X";
JSON.stringify(obj);

Les résultats de ces deux appels stringify sont différents, et apparaissent dans un diff de mes données, mais mon application ne se soucie pas de l'ordre des propriétés. Les objets sont construits de plusieurs façons et à plusieurs endroits.

18voto

aleung Points 963

Mise à jour 2018-7-24 :

Cette version trie les objets imbriqués et supporte également les tableaux :

function sortObjByKey(value) {
  return (typeof value === 'object') ?
    (Array.isArray(value) ?
      value.map(sortObjByKey) :
      Object.keys(value).sort().reduce(
        (o, key) => {
          const v = value[key];
          o[key] = sortObjByKey(v);
          return o;
        }, {})
    ) :
    value;
}

function orderedJsonStringify(obj) {
  return JSON.stringify(sortObjByKey(obj));
}

Cas de test :

  describe('orderedJsonStringify', () => {
    it('make properties in order', () => {
      const obj = {
        name: 'foo',
        arr: [
          { x: 1, y: 2 },
          { y: 4, x: 3 },
        ],
        value: { y: 2, x: 1, },
      };
      expect(orderedJsonStringify(obj))
        .to.equal('{"arr":[{"x":1,"y":2},{"x":3,"y":4}],"name":"foo","value":{"x":1,"y":2}}');
    });

    it('support array', () => {
      const obj = [
        { x: 1, y: 2 },
        { y: 4, x: 3 },
      ];
      expect(orderedJsonStringify(obj))
        .to.equal('[{"x":1,"y":2},{"x":3,"y":4}]');
    });

  });

Réponse obsolète :

Une version concise en ES2016. Crédit à @codename , de https://stackoverflow.com/a/29622653/94148

function orderedJsonStringify(o) {
  return JSON.stringify(Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {}));
}

4voto

Giridhar C R Points 180

Cette réponse est identique à celle de Satpal Singh.

function stringifyJSON(obj){
    keys = [];
    if(obj){
        for(var key in obj){
            keys.push(key);
        }
    }
    keys.sort();
    var tObj = {};
    var key;
    for(var index in keys){
        key = keys[index];
        tObj[ key ] = obj[ key ];
    }
    return JSON.stringify(tObj);
}

obj1 = {}; obj1.os="linux"; obj1.name="X";
stringifyJSON(obj1); //returns "{"name":"X","os":"linux"}"

obj2 = {}; obj2.name="X"; obj2.os="linux";
stringifyJSON(obj2); //returns "{"name":"X","os":"linux"}"

4voto

Jason Parham Points 318

Une réponse récursive et simplifiée :

function sortObject(obj) {
    if(typeof obj !== 'object')
        return obj
    var temp = {};
    var keys = [];
    for(var key in obj)
        keys.push(key);
    keys.sort();
    for(var index in keys)
        temp[keys[index]] = sortObject(obj[keys[index]]);       
    return temp;
}

var str = JSON.stringify(sortObject(obj), undefined, 4);

4voto

Mayki Nayki Points 727

Vous pouvez trier un objet par nom de propriété dans EcmaScript 2015

function sortObjectByPropertyName(obj) {
    return Object.keys(obj).sort().reduce((c, d) => (c[d] = obj[d], c), {});
}

3voto

Dave R. Points 4621

Vous pouvez ajouter un toJSON à votre objet que vous pouvez utiliser pour personnaliser la sortie. À l'intérieur de la fonction, l'ajout des propriétés actuelles à un nouvel objet dans un ordre spécifique devrait préserver cet ordre lors de la stringification.

Voir ici :

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/JSON/stringify

Il n'existe pas de méthode intégrée pour contrôler l'ordonnancement, car les données JSON sont conçues pour être accessibles par clés.

Voici un jsfiddle avec un petit exemple :

http://jsfiddle.net/Eq2Yw/

Essayez de commenter le toJSON l'ordre des propriétés est inversé. Sachez que cette fonction peut être spécifique à un navigateur, c'est-à-dire que l'ordre n'est pas officiellement pris en charge dans la spécification. Cela fonctionne dans la version actuelle de Firefox, mais si vous voulez une solution 100% robuste, vous devrez peut-être écrire votre propre fonction stringifier.

Edit :

Voir aussi cette question SO concernant la sortie non déterministe de stringify, en particulier les détails de Daff sur les différences de navigateur :

Comment vérifier de façon déterministe qu'un objet JSON n'a pas été modifié ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X