Mi aplicación tiene una gran variedad de objetos, que clasifico y guardo en el disco. Desafortunadamente, cuando los objetos de la matriz se manipulan y, a veces, se reemplazan, las propiedades de los objetos se enumeran en diferentes órdenes (¿su orden de creación?). Cuando hago JSON.stringify () en la matriz y la guardo, una diferencia muestra las propiedades que se enumeran en diferentes órdenes, lo cual es molesto cuando trato de fusionar los datos más con las diferencias y las herramientas de fusión.
Idealmente, me gustaría ordenar las propiedades de los objetos en orden alfabético antes de realizar la secuenciación, o como parte de la operación de secuenciación. Hay código para manipular los objetos de la matriz en muchos lugares, y sería difícil alterarlos para crear siempre propiedades en un orden explícito.
¡Cualquier sugerencia será bienvenida!
Un ejemplo condensado:
obj = {}; obj.name="X"; obj.os="linux";
JSON.stringify(obj);
obj = {}; obj.os="linux"; obj.name="X";
JSON.stringify(obj);
La salida de estas dos llamadas de stringify es diferente y se muestra en una diferencia de mis datos, pero mi aplicación no se preocupa por el orden de las propiedades. Los objetos se construyen de muchas formas y lugares.
fuente
Respuestas:
El enfoque más simple, moderno y actualmente compatible con el navegador es simplemente este:
Sin embargo, este método elimina los objetos anidados a los que no se hace referencia y no se aplica a los objetos dentro de las matrices. También querrá aplanar el objeto de clasificación si desea algo como este resultado:
Puedes hacer eso con esto:
Para hacerlo programáticamente con algo que puede modificar usted mismo, debe insertar los nombres de las propiedades del objeto en una matriz, luego ordenar la matriz alfabéticamente e iterar a través de esa matriz (que estará en el orden correcto) y seleccionar cada valor del objeto en ese orden. "hasOwnProperty" también está marcado, por lo que definitivamente solo tiene las propiedades propias del objeto. He aquí un ejemplo:
Nuevamente, esto debería garantizar que se repita en orden alfabético.
Finalmente, yendo más allá de la manera más simple, esta biblioteca le permitirá de forma recursiva ordenar cualquier JSON que le pase: https://www.npmjs.com/package/json-stable-stringify
Salida
fuente
obj[i]
en el bucle for porquei
es un número entero y los nombres de propiedad no lo son necesariamente (de ahí esta pregunta). Debería serloobj[arr[i]]
.iterateObjectAlphabetically
en una función reutilizable. Sin la devolución de llamada, el 'código de carga útil' tendría que estar dentro de la propia función. Creo que es una solución muy elegante y que se usa en muchas bibliotecas y en el propio núcleo de JS. Por ejemplo, Array.forEach .Creo que si tiene el control de la generación JSON (y parece que lo tiene), entonces, para sus propósitos, esta podría ser una buena solución: json-stable-stringify
Desde el sitio web del proyecto:
Si el JSON producido es determinista, debería poder diferenciarlo / fusionarlo fácilmente.
fuente
Puede pasar una matriz ordenada de los nombres de propiedad como segundo argumento de
JSON.stringify()
:fuente
JSON.stringify()
se llama al segundo parámetro dereplacer
y puede ser una matriz. Se usa para construir unPropertyList
que luego se usaSerializeJSONObject()
para agregar las propiedades en ese orden. Esto está documentado desde ECMAScript 5.> JSON.stringify({a: {c: 1, b: 2}}, ['a']) '{"a":{}}'
una forma (hacky) de crear la lista de todas las claves relevantes es usar JSON.stringify para atravesar el objeto:function orderedStringify(obj) { const allKeys = []; JSON.stringify(obj, (k, v) => { allKeys.push(k); return v; }); return JSON.stringify(obj, allKeys.sort()); }
Ejemplo:> orderedStringify({a: {c: 1, b: 2}}) '{"a":{"b":2,"c":1}}'
No entiendo por qué se necesita la complejidad de las mejores respuestas actuales para obtener todas las claves de forma recursiva. A menos que se necesite un rendimiento perfecto, me parece que podemos llamar
JSON.stringify()
dos veces, la primera para obtener todas las claves y la segunda para hacer realmente el trabajo. De esa manera, toda la complejidad de la recursividad es manejada porstringify
, y sabemos que conoce sus cosas y cómo manejar cada tipo de objeto:fuente
Object.keys()
no es recursivo, por lo que si tiene un objeto como{a: "A", b: {c: "C"} }
y llama a Object.keys en él, solo obtendrá las clavesa
yb
, pero noc
.JSON.stringify
sabe todo sobre la recursividad en cada tipo de objeto manejado por el proceso de serialización JSON, ya sea un objeto o una matriz (y ya implementa la lógica para reconocer ambos), por lo que debería manejar todo correctamente para nosotros.Actualización 2018-7-24:
Esta versión clasifica objetos anidados y también admite matrices:
Caso de prueba:
Respuesta obsoleta:
Una versión concisa en ES2016. Crédito a @codename, de https://stackoverflow.com/a/29622653/94148
fuente
function orderedJsonStringify(o) { return JSON.stringify(Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {})); }
sortObjByKey()
compruebe las referencias circulares, así que tenga cuidado, puede colgarse en un bucle infinito dependiendo de los datos de entrada. Ejemplo: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
fuente
Esto es lo mismo que la respuesta de Satpal Singh
fuente
Puede agregar una
toJSON
función personalizada a su objeto que puede usar para personalizar la salida. Dentro de la función, agregar propiedades actuales a un nuevo objeto en un orden específico debería preservar ese orden cuando se cadena.Mira aquí:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/JSON/stringify
No hay un método incorporado para controlar los pedidos porque los datos JSON deben ser accedidos por claves.
Aquí hay un jsfiddle con un pequeño ejemplo:
http://jsfiddle.net/Eq2Yw/
Intente comentar la
toJSON
función: el orden de las propiedades se invierte. Tenga en cuenta que esto puede ser específico del navegador, es decir, que la especificación no admite oficialmente el pedido. Funciona en la versión actual de Firefox, pero si desea una solución 100% robusta, es posible que deba escribir su propia función de secuenciador.Editar:
También vea esta pregunta de SO sobre la salida no determinista de stringify, especialmente los detalles de Daff sobre las diferencias del navegador:
¿Cómo verificar determinísticamente que un objeto JSON no ha sido modificado?
fuente
Una respuesta recursiva y simplificada:
fuente
reorder
debe cambiarse el nombre asortObject
y esto no maneja matricestypeof arr === "object"
transformaría matrices en objetos. Por ejemplovar obj = {foo: ["bar", "baz"]}
, estaría encadenado en{ "foo": { "0": "bar", "1": "baz"} }
if(obj.constructor.prototype !== Object.prototype)
Puede ordenar el objeto por nombre de propiedad en EcmaScript 2015
fuente
sortObjectPropertiesByName()
o más simplesortPropertiesByName()
.Tomé la respuesta de @Jason Parham e hice algunas mejoras
Esto soluciona el problema de que las matrices se conviertan en objetos y también le permite definir cómo ordenar las matrices.
Ejemplo:
salida:
fuente
La respuesta aceptada no me funciona para objetos anidados por alguna razón. Esto me llevó a codificar el mío. Como es a fines de 2019 cuando escribo esto, hay algunas opciones más disponibles dentro del idioma.
Actualización: Creo que la respuesta de David Furlong es un enfoque preferible a mi intento anterior, y lo he descartado. El mío depende del soporte para Object.entries (...), por lo que no es compatible con Internet Explorer.
-
MANTENER ESTA VERSIÓN ANTIGUA PARA REFERENCIA HISTÓRICA
Descubrí que una matriz simple y plana de todas las claves en el objeto funcionará. En casi todos los navegadores (no en Edge o Internet Explorer, como era de esperar) y Node 12+, hay una solución bastante corta ahora que Array.prototype.flatMap (...) está disponible. (El equivalente de lodash también funcionaría). Solo he probado en Safari, Chrome y Firefox, pero no veo ninguna razón por la que no funcione en ningún otro lugar que admita flatMap y JSON.stringify estándar (...) .
Con esto, puede secuenciar sin dependencias de terceros e incluso pasar su propio algoritmo de ordenación que ordena los pares de entrada clave-valor, de modo que pueda ordenar por clave, carga útil o una combinación de los dos. Funciona para objetos anidados, matrices y cualquier combinación de tipos de datos antiguos.
Huellas dactilares:
Si debe tener compatibilidad con motores JavaScript más antiguos , puede usar estas versiones un poco más detalladas que emulan el comportamiento de flatMap. El cliente debe admitir al menos ES5, por lo que no Internet Explorer 8 o inferior.
Estos devolverán el mismo resultado que el anterior.
fuente
Funciona con lodash, objetos anidados, cualquier valor de atributo de objeto:
Depende del comportamiento de Chrome y Node que la primera clave asignada a un objeto se genere primero por
JSON.stringify
.fuente
Tratar:
fuente
Hice una función para ordenar el objeto y con devolución de llamada ... que en realidad crea un nuevo objeto
y llámalo con objeto.
que imprime
{"value":"msio","os":"windows","name":"anu"}
y para clasificar con valor.que imprime
{"os":"windows","value":"msio","name":"anu"}
fuente
Si los objetos de la lista no tienen las mismas propiedades, genere un objeto maestro combinado antes de encadenar:
fuente
// ejemplo como a continuación. en cada capa, para objetos como {}, aplanados en orden de clave. para matrices, números o cadenas, aplanadas como / con JSON.stringify.
fuente
Extendiendo la respuesta de AJP, para manejar matrices:
fuente
Sorprendido que nadie haya mencionado la
isEqual
función de Lodash .Con el problema original, las claves están ordenadas de manera inconsistente, es una gran solución y, por supuesto, se detendrá si encuentra un conflicto en lugar de serializar ciegamente todo el objeto.
Para evitar importar toda la biblioteca, haga esto:
Ejemplo de bonificación: también puede usar esto con RxJS con este operador personalizado
fuente
Después de todo, necesita una matriz que almacene en caché todas las claves en el objeto anidado (de lo contrario, omitirá las claves no almacenadas en caché). La respuesta más antigua es simplemente incorrecta, porque el segundo argumento no se preocupa por la notación de puntos. Entonces, la respuesta (usando Set) se convierte en.
fuente
Aquí hay un enfoque de clonación ... clone el objeto antes de convertirlo a json:
Si es muy nuevo pero parece funcionar bien en archivos package.json.
fuente
Hay un
Array.sort
método que puede resultarle útil. Por ejemplo:fuente