vacio saber recorrer objeto new esta eliminar elemento dinamico crear javascript json

javascript - saber - ¿Cómo verificar determinísticamente que un objeto JSON no ha sido modificado?



recorrer objeto json javascript (8)

Algunas cosas que quizás desee considerar: ¿qué significa que un objeto sea diferente? ¿Estás buscando para ver si una propiedad en ese objeto ha cambiado? ¿A quién le interesa ''saber'' sobre estos cambios? ¿Desea saber de inmediato si una propiedad de objetos ha cambiado?

Puede hacer que las propiedades de ese objeto sean "observables" y cuando esa propiedad cambie puede activar un evento y quien esté interesado puede suscribirse a esos cambios de propiedad. De esa forma, sabrá de inmediato qué ha cambiado y podrá hacer lo que quiera con esa información. Knockout.js usa este enfoque. De esta forma, no tiene que recurrir a comparaciones de objetos "desagradables"

Según la documentación de MDN para JSON.stringify :

No se garantiza que las propiedades de los objetos que no son de matriz estén codificadas en un orden en particular. No confíe en el pedido de propiedades dentro del mismo objeto dentro de la stringificación.

Tenía la esperanza de determinar si un objeto cambió al almacenar en caché una versión codificada del objeto, y luego compararlo con una versión posteriormente codificada del objeto. Eso parecía mucho más simple que iterar recursivamente a través del objeto y hacer comparaciones. El problema es que debido a que la función JSON.stringify no es determinista, técnicamente podría obtener una cadena diferente cuando participo en el mismo objeto.

¿Qué otras opciones tengo? ¿O debo escribir una desagradable función de comparación para determinar la igualdad de los objetos?


Aquí hay una implementación de un JSON.stringify determinístico () que escribí (usa Underscore.js ). Convierte los objetos (que no son de matriz) recursivamente en pares de clave-valor ordenados (como matrices) y luego los codifica. Publicación original de codificador here .

Stringify:

function stringify(obj) { function flatten(obj) { if (_.isObject(obj)) { return _.sortBy(_.map( _.pairs(obj), function(p) { return [p[0], flatten(p[1])]; } ), function(p) { return p[0]; } ); } return obj; } return JSON.stringify(flatten(obj)); }

Analizar gramaticalmente:

function parse(str) { function inflate(obj, pairs) { _.each(pairs, function(p) { obj[p[0]] = _.isArray(p[1]) ? inflate({}, p[1]) : p[1]; }); return obj; } return inflate({}, JSON.parse(str)); }


En estos días he estado jugando con la forma determinista de codificar un objeto y he escrito el objeto ordenado stringify en JSON, que resuelve el dilema mencionado anteriormente: http://stamat.wordpress.com/javascript-object-ordered-property-stringify/

También estaba jugando con implementaciones de tablas hash personalizadas que también están relacionadas con el tema: http://stamat.wordpress.com/javascript-quickly-find-very-large-objects-in-a-large-array/

//SORT WITH STRINGIFICATION var orderedStringify = function(o, fn) { var props = []; var res = ''{''; for(var i in o) { props.push(i); } props = props.sort(fn); for(var i = 0; i < props.length; i++) { var val = o[props[i]]; var type = types[whatis(val)]; if(type === 3) { val = orderedStringify(val, fn); } else if(type === 2) { val = arrayStringify(val, fn); } else if(type === 1) { val = ''"''+val+''"''; } if(type !== 4) res += ''"''+props[i]+''":''+ val+'',''; } return res.substring(res, res.lastIndexOf('',''))+''}''; }; //orderedStringify for array containing objects var arrayStringify = function(a, fn) { var res = ''[''; for(var i = 0; i < a.length; i++) { var val = a[i]; var type = types[whatis(val)]; if(type === 3) { val = orderedStringify(val, fn); } else if(type === 2) { val = arrayStringify(val); } else if(type === 1) { val = ''"''+val+''"''; } if(type !== 4) res += ''''+ val+'',''; } return res.substring(res, res.lastIndexOf('',''))+'']''; }


Es posible que desee probar JSON.sortify , un pequeño ayudante que escribí.

En contraste con las respuestas dadas hasta ahora,


Estoy bastante seguro de que esto se debe a la forma en que los diferentes motores de JavaScript realizan un seguimiento interno de las propiedades de los objetos. Toma esto por ejemplo:

var obj = { "1" : "test", "0" : "test 2" }; for(var key in obj) { console.log(key); }

Esto registrará 1, 0 en, por ejemplo, Firefox, pero 0, 1 en V8 (Chrome y NodeJS). Entonces, si necesita ser determinista, probablemente deba iterar a través de cada almacén de claves en una matriz, ordenar la matriz y luego hacer una cadena de cada propiedad separadamente al recorrer esa matriz.


Las claves JavaScript están intrínsecamente desordenadas. Tienes que escribir tu propio Stringifier para que esto funcione, así lo hice.

Uso:

JSONc14n.stringify(obj)

Fuente:

var JSONc14n = { stringify: function(obj){ var json_string, keys, key, i; switch(this.get_type(obj)){ case "[object Array]": json_string = "["; for(i = 0; i < obj.length; i++){ json_string += this.stringify(obj[i]); if(i < obj.length - 1) json_string += ","; } json_string += "]"; break; case "[object Object]": json_string = "{"; keys = Object.keys(obj); keys.sort(); for(i = 0; i < keys.length; i++){ json_string += ''"'' + keys[i] + ''":'' + this.stringify(obj[keys[i]]); if(i < keys.length - 1) json_string += ","; } json_string += "}"; break; case "[object Number]": json_string = obj.toString(); break; default: json_string = ''"'' + obj.toString().replace(/["//]/g, function(_this){ return function(character){ return _this.escape_character.apply(_this, [character]); }; }(this) ) + ''"''; } return json_string; }, get_type: function(thing){ if(thing===null) return "[object Null]"; return Object.prototype.toString.call(thing); }, escape_character: function(character){ return this.escape_characters[character]; }, escape_characters: { ''"'': ''//"'', ''//': ''////' } };


Recientemente tuve un caso de uso similar. El siguiente código no tiene dependencias y funciona para todos los navegadores:

function stringify(obj) { var type = Object.prototype.toString.call(obj); // IE8 <= 8 does not have array map var map = Array.prototype.map || function map(callback) { var ret = []; for (var i = 0; i < this.length; i++) { ret.push(callback(this[i])); } return ret; }; if (type === ''[object Object]'') { var pairs = []; for (var k in obj) { if (!obj.hasOwnProperty(k)) continue; pairs.push([k, stringify(obj[k])]); } pairs.sort(function(a, b) { return a[0] < b[0] ? -1 : 1 }); pairs = map.call(pairs, function(v) { return ''"'' + v[0] + ''":'' + v[1] }); return ''{'' + pairs + ''}''; } if (type === ''[object Array]'') { return ''['' + map.call(obj, function(v) { return stringify(v) }) + '']''; } return JSON.stringify(obj); };

stringify([{b: {z: 5, c: 2, a: {z: 1, b: 2}}, a: 1}, [1, 2, 3]])

''[{"a":1,"b":{"a":{"b":2,"z":1},"c":2,"z":5}},[1,2,3]]''

stringify([{a: 1, b:{z: 5, c: 2, a: {b: 2, z: 1}}}, [1, 2, 3]])

''[{"a":1,"b":{"a":{"b":2,"z":1},"c":2,"z":5}},[1,2,3]]''


Usando Underscore o Lodash:

var sortByKeys = function(obj) { if (!_.isObject(obj)) { return obj; } var sorted = {}; _.each(_.keys(obj).sort(), function(key) { sorted[key] = sortByKeys(obj[key]); }); return sorted; }; var sortedStringify = function() { arguments[0] = sortByKeys(arguments[0]); return JSON.stringify.apply(this, arguments); };

Funciona en los últimos Chrome y Firefox.

JSFiddle aquí: http://jsfiddle.net/stchangg/ruC22/2/