2012-09-11 15 views
12

He estado trabajando con un poco de análisis JSON y pasando Javascript en Node.js y navegadores recientemente y tropecé con este enigma.¿Por qué JSON.stringify no serializa los valores del prototipo?

Cualquier objeto que haya creado usando un constructor, no se puede serializar por completo a través de JSON.stringify, ¡A MENOS que haya inicializado todos los valores dentro del constructor de forma individual! Esto significa que mi prototipo se vuelve esencialmente inútil al diseñar estas clases.

¿Alguien puede arrojar algo de luz sobre por qué lo siguiente no se serializa como espero?

var ClassA = function() { this.initialisedValue = "You can see me!" }; 
ClassA.prototype = { initialisedValue : "You can't see me!", uninitialisedValue : "You can't see me!" }; 
var a = new ClassA(); 
var a_string = JSON.stringify(a); 

Lo que sucede:

una_cadena == { "initialisedValue": "Usted me puede ver!" }

yo esperaría:

una_cadena == { "initialisedValue": "Usted me puede ver!", "UninitialisedValue": "Usted no me puede ver!" }

+0

posible duplicado de [? Cómo stringify objetos heredados a JSON] (http://stackoverflow.com/questions/8779249/how-to-stringify-inherited-objects-to-json) – lonesomeday

+0

http://stackoverflow.com/questions/5790620/how-to-stringify-a-whole- javascript-object-including-proto-properties – speg

+0

Entiendo que los métodos no se pueden serializar a través de JSON, pero gracias un solo día, como me ha señalado una discusión ab esto. Obviamente, es un 'problema' documentado, no estoy seguro de por qué mis búsquedas no mencionaron esto. ¡Gracias! – killercowuk

Respuesta

14

Simplemente porque esta es la forma en que funciona JSON. Desde el ES5 spec:

Sea K una lista interna de cadenas que consta de los nombres de todos los propias propiedades de valor cuyo [[Enumerable]] atributo es cierto.

Esto tiene sentido, porque no hay ningún mecanismo en la especificación JSON para conservar la información que sería necesaria para analizar una cadena JSON de nuevo en un objeto JavaScript si se incluyeron las propiedades heredadas. En su ejemplo, ¿cómo se analizaría esto?

{"initialisedValue": "¡Me puedes ver!", "UninitialisedValue": "¡No me puedes ver!" }

No hay información para analizarlo en otra cosa que no sea un objeto plano con 2 pares de clave-valor.

Y si lo piensas bien, JSON no tiene la intención de mapear directamente objetos de JavaScript. Otros lenguajes deben poder analizar cadenas JSON en estructuras simples de pares nombre-valor. Si las cadenas JSON contienen toda la información necesaria para serializar las cadenas completas de alcance de JavaScript, otros idiomas pueden ser menos capaces de analizar eso en algo útil. En palabras de Douglas Crockford en json.org:

Estas [tablas y matrices hash] son ​​estructuras de datos universales. Prácticamente todos los lenguajes de programación modernos los respaldan de una forma u otra. Tiene sentido que un formato de datos que sea intercambiable con los lenguajes de programación también se base en estas estructuras.

+0

Gracias James, creo que esto pone este problema a la cama. ¡Qué vergüenza, ya que los prototipos son esencialmente inútiles en mi caso! ¡Tendrás que recurrir a constructores inflados entonces! – killercowuk

+0

@killercowuk - Podría crear su propio formato en cordel para sus objetos. He editado mi respuesta para incluir alguna razón más detrás de los motivos de esto. –

+0

Saludos James, obtengo lo racional, sin embargo me siento un poco mal por la abreviatura JSON - JavaScript Object Notation; sin embargo, aprecio completamente que es fundamentalmente un "formato ligero de intercambio de datos" (json.org) – killercowuk

0

que aterrizó en esta página durante el uso de la mangosta: si otros usuarios tienen problema similar, la siguiente pregunta (y respuestas relacionadas) podrían ser útiles:

How do you turn a Mongoose document into a plain object?

(básicamente: utilizar toObject del Modelo() método)

0

Me gustaría agregar que, aunque JSON.stringify solo codificará las propiedades del objeto, como se explica en la respuesta aceptada, puede modificar el comportamiento del proceso de stringificación especificando una matriz de String como el segundo parámetro de JSON.stringify (llamado matriz de sustitución).

Si especifica una matriz de String con la lista blanca de propiedades para stringify, el algoritmo de stringification cambiará su comportamiento y considerará las propiedades de la cadena del prototipo.

De ES5 spec:

  1. Si PropertyList no está definida, entonces

    a. Deje K ser PropertyList.

  2. Else

    a. Deje K ser una Lista interna de cadenas que consiste en los nombres de todas las propiedades propias de valor cuyo atributo [[Enumerable]] es true. El orden de las cadenas debe ser el mismo que el usado por la función incorporada estándar Object.keys.

Si conoce el nombre de las propiedades del objeto a stringify de antemano, se puede hacer algo como esto:

var a_string = JSON.stringify(a, ["initialisedValue", "uninitialisedValue"]); 
// a_string == { "initialisedValue" : "You can see me!", "uninitialisedValue" : "You can't see me!" } 
Cuestiones relacionadas