Mon application dispose d'un large éventail d'objets, que je stringifie 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 répertorié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 répertoriées dans des ordres différents, ce qui est ennuyeux lorsque je tente de fusionner les données davantage avec des outils de diff et de fusion.
Idéalement, je voudrais trier les propriétés des objets par ordre alphabétique avant d'effectuer le stringify, ou dans le cadre de l'opération stringify. Il existe du code pour manipuler les objets du tableau à de nombreux endroits, et les modifier pour toujours créer des propriétés dans un ordre explicite serait difficile.
Les suggestions seraient 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);
La sortie de ces deux appels stringify est différente et apparaît 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 nombreuses manières et à différents endroits.
la source
Réponses:
L'approche la plus simple, moderne et actuellement prise en charge par le navigateur est simplement la suivante:
Cependant, cette méthode supprime tous les objets imbriqués qui ne sont pas référencés et ne s'applique pas aux objets dans les tableaux. Vous voudrez également aplatir l'objet de tri si vous voulez quelque chose comme cette sortie:
Vous pouvez le faire avec ceci:
Pour le faire par programme avec quelque chose que vous pouvez modifier vous-même, vous devez pousser les noms de propriété de l'objet dans un tableau, puis trier le tableau par ordre alphabétique et parcourir ce tableau (qui sera dans le bon ordre) et sélectionner chaque valeur de l'objet dans cet ordre. "hasOwnProperty" est également coché afin que vous n'ayez définitivement que les propres propriétés de l'objet. Voici un exemple:
Encore une fois, cela devrait garantir que vous parcourez dans l'ordre alphabétique.
Enfin, pour aller plus loin pour la manière la plus simple, cette bibliothèque vous permettra de trier récursivement tout JSON que vous lui passez: https://www.npmjs.com/package/json-stable-stringify
Production
la source
obj[i]
dans la boucle for car ili
s'agit d'un entier et les noms de propriété ne le sont pas nécessairement (d'où cette question). Ça devrait êtreobj[arr[i]]
.iterateObjectAlphabetically
en une fonction réutilisable. Sans le rappel, le «code de la charge utile» devrait être à l'intérieur de la fonction elle-même. Je pense que c'est une solution très élégante et qui est utilisée dans de nombreuses bibliothèques et le noyau JS lui-même. Par exemple, Array.forEach .Je pense que si vous contrôlez la génération JSON (et cela ressemble à vous), alors pour vos besoins, cela pourrait être une bonne solution: json-stable-stringify
Depuis le site Web du projet:
Si le JSON produit est déterministe, vous devriez pouvoir le comparer / le fusionner facilement.
la source
Vous pouvez passer un tableau trié des noms de propriétés comme deuxième argument de
JSON.stringify()
:la source
JSON.stringify()
est appeléreplacer
et peut être un tableau. Il est utilisé pour créer unPropertyList
qui est ensuite utiliséSerializeJSONObject()
pour ajouter les propriétés dans cet ordre. Ceci est documenté depuis ECMAScript 5.> JSON.stringify({a: {c: 1, b: 2}}, ['a']) '{"a":{}}'
Une façon (hacky) de construire la liste de toutes les clés pertinentes est d'utiliser JSON.stringify pour traverser l'objet:function orderedStringify(obj) { const allKeys = []; JSON.stringify(obj, (k, v) => { allKeys.push(k); return v; }); return JSON.stringify(obj, allKeys.sort()); }
Exemple:> orderedStringify({a: {c: 1, b: 2}}) '{"a":{"b":2,"c":1}}'
Je ne comprends pas pourquoi la complexité des meilleures réponses actuelles est nécessaire, pour obtenir toutes les clés de manière récursive. À moins que des performances parfaites ne soient nécessaires, il me semble que nous pouvons simplement appeler
JSON.stringify()
deux fois, la première fois pour obtenir toutes les clés, et la deuxième fois, pour vraiment faire le travail. De cette façon, toute la complexité de la récursivité est gérée parstringify
, et nous savons qu'il connaît son contenu et comment gérer chaque type d'objet:la source
Object.keys()
n'est pas récursif, donc si vous avez un objet comme{a: "A", b: {c: "C"} }
et que vous appelez Object.keys dessus, vous n'obtiendrez que les clésa
etb
, mais pasc
.JSON.stringify
sait tout sur la récursivité sur chaque type d'objet géré par le processus de sérialisation JSON, qu'il s'agisse d'un objet ou d'un tableau (et il implémente déjà la logique pour reconnaître les deux), il doit donc tout gérer correctement pour nous.Mise à jour 2018-7-24:
Cette version trie les objets imbriqués et prend également en charge les tableaux:
Cas de test:
Réponse obsolète:
Une version concise dans ES2016. Crédit à @codename, de https://stackoverflow.com/a/29622653/94148
la source
function orderedJsonStringify(o) { return JSON.stringify(Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {})); }
sortObjByKey()
vérifie les références circulaires, donc soyez prudent, il peut se bloquer dans une boucle infinie en fonction des données d'entrée. Exemple:var objA = {}; var objB = {objA: objA}; objA.objB = objB;
->sortObjByKey(objA);
->VM59:6 Uncaught RangeError: Maximum call stack size exceeded
https://gist.github.com/davidfurlong/463a83a33b70a3b6618e97ec9679e490
la source
C'est la même chose que la réponse de Satpal Singh
la source
Vous pouvez ajouter une personnalisation
toJSON
fonction à 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 doit conserver cet ordre lorsqu'il est stringifié.Vois ici:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/JSON/stringify
Il n'y a pas de méthode intégrée pour contrôler l'ordre, car les données JSON sont censées être accessibles par des clés.
Voici un jsfiddle avec un petit exemple:
http://jsfiddle.net/Eq2Yw/
Essayez de commenter la
toJSON
fonction - l'ordre des propriétés est inversé. Veuillez noter que cela peut être spécifique au navigateur, c'est-à-dire que la commande n'est pas officiellement prise 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.Éditer:
Voir également 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 manière déterministe qu'un objet JSON n'a pas été modifié?
la source
Une réponse récursive et simplifiée:
la source
reorder
devrait être renommésortObject
et cela ne gère pas les tableauxtypeof arr === "object"
cela transformerait les tableaux en objets. Par exemplevar obj = {foo: ["bar", "baz"]}
serait stringifié en{ "foo": { "0": "bar", "1": "baz"} }
if(obj.constructor.prototype !== Object.prototype)
Vous pouvez trier l'objet par nom de propriété dans EcmaScript 2015
la source
sortObjectPropertiesByName()
ou plus simplesortPropertiesByName()
.J'ai pris la réponse de @Jason Parham et j'ai apporté quelques améliorations
Cela résout le problème de la conversion des tableaux en objets et vous permet également de définir comment trier les tableaux.
Exemple:
production:
la source
La réponse acceptée ne fonctionne pas pour moi pour les objets imbriqués pour une raison quelconque. Cela m'a amené à coder le mien. Comme il est fin 2019 lorsque j'écris ceci, il y a quelques autres options disponibles dans la langue.
Mise à jour: Je pense que la réponse de David Furlong est une approche préférable à ma tentative précédente, et je l'ai écartée. Le mien repose sur le support d'Object.entries (...), donc pas de support d'Internet Explorer.
-
CONSERVER CETTE ANCIENNE VERSION POUR RÉFÉRENCE HISTORIQUE
J'ai trouvé qu'un tableau simple et plat de toutes les clés de l'objet fonctionnera. Dans presque tous les navigateurs (pas Edge ou Internet Explorer, comme on pouvait s'y attendre ) et Node 12+, il existe une solution assez courte maintenant que Array.prototype.flatMap (...) est disponible. (L'équivalent lodash fonctionnerait aussi.) Je n'ai testé que dans Safari, Chrome et Firefox, mais je ne vois aucune raison pour laquelle cela ne fonctionnerait pas ailleurs qui prend en charge flatMap et JSON.stringify standard (...) .
Avec cela, vous pouvez stringify sans dépendances tierces et même passer votre propre algorithme de tri qui trie sur les paires d'entrées clé-valeur, de sorte que vous pouvez trier par clé, charge utile ou une combinaison des deux. Fonctionne pour les objets imbriqués, les tableaux et tout mélange d'anciens types de données.
Impressions:
Si vous devez être compatible avec les moteurs JavaScript plus anciens , vous pouvez utiliser ces versions légèrement plus détaillées qui émulent le comportement de flatMap. Le client doit prendre en charge au moins ES5, donc pas d'Internet Explorer 8 ou inférieur.
Ceux-ci renverront le même résultat que ci-dessus.
la source
Fonctionne avec lodash, objets imbriqués, toute valeur d'attribut d'objet:
Il repose sur le comportement de Chrome et de Node selon lequel la première clé affectée à un objet est sortie en premier
JSON.stringify
.la source
Essayer:
la source
J'ai créé une fonction pour trier l'objet, et avec callback .. qui crée en fait un nouvel objet
et appelez-le avec un objet.
qui imprime
{"value":"msio","os":"windows","name":"anu"}
, et pour le tri avec valeur.qui imprime
{"os":"windows","value":"msio","name":"anu"}
la source
Si les objets de la liste n'ont pas les mêmes propriétés, générez un objet maître combiné avant stringify:
la source
// exemple comme ci-dessous. dans chaque couche, pour des objets comme {}, aplatis dans le tri par clé. pour les tableaux, les nombres ou les chaînes, aplatis comme / avec JSON.stringify.
la source
Extension de la réponse d'AJP, pour gérer les tableaux:
la source
Surpris, personne n'a mentionné la
isEqual
fonction de lodash .Avec le problème d'origine - les clés étant ordonnées de manière incohérente - c'est une excellente solution - et bien sûr, il s'arrêtera simplement s'il trouve un conflit au lieu de sérialiser aveuglément l'objet entier.
Pour éviter d'importer toute la bibliothèque, procédez comme suit:
Exemple bonus: vous pouvez également l'utiliser avec RxJS avec cet opérateur personnalisé
la source
Après tout, il a besoin d'un tableau qui met en cache toutes les clés de l'objet imbriqué (sinon il omettra les clés non mises en cache.) La réponse la plus ancienne est tout simplement fausse, car le second argument ne se soucie pas de la notation par points. Ainsi, la réponse (en utilisant Set) devient.
la source
Voici une approche de clonage ... clonez l'objet avant de le convertir en json:
Si est très nouveau mais semble fonctionner correctement sur les fichiers package.json.
la source
Il existe une
Array.sort
méthode qui peut vous être utile. Par exemple:la source