2010-09-10 4 views
18

Estoy buscando una solución para serializar (y deserializar) objetos de Javascript en una cadena entre navegadores, incluidos los miembros del objeto que resultan ser funciones. Un objeto típico tendrá el siguiente aspecto:Javascript: objeto stringify (incluidos los miembros de la función de tipo)

{ 
    color: 'red', 
    doSomething: function (arg) { 
     alert('Do someting called with ' + arg); 
    } 
} 

doSomething() sólo contendrá las variables locales (no es necesario para serializar también el contexto de llamada!).

JSON.stringify() ignorará el miembro 'doSomething' porque es una función. Sé que el método toSource() hará lo que yo quiera, pero es específico de FF.

+1

Voy a dejar un comentario porque no estoy ofreciendo una solución completa. Una cosa que puede ayudar es que puede stringificar una función con una llamada a 'toString()'. http://jsfiddle.net/HFMaz/ No estoy seguro acerca de la compatibilidad entre navegadores. – user113716

+1

esto se pregunta con regularidad pero no encuentro nada relevante: \ ¿Por qué necesita serializar la función de todos modos? tal vez hay una mejor manera de organizar su código? – lincolnk

+0

Esto es para proyecto WYSIWYG. Cada objeto Javascript (con métodos) define el comportamiento de los componentes de la página. El contenido de la página (incluido el comportamiento de JS) debe guardarse en el lado del servidor, por lo tanto serializado. –

Respuesta

5

Una manera rápida y sucia sería así:

Object.prototype.toJSON = function() { 
    var sobj = {}, i; 
    for (i in this) 
    if (this.hasOwnProperty(i)) 
     sobj[i] = typeof this[i] == 'function' ? 
     this[i].toString() : this[i]; 

return sobj; 

}; 

Obviamente, esto afectará a la serialización de cada objeto en su código, y podría tropezar código niave usando for in bucles sin filtrar. La forma "correcta" sería escribir una función recursiva que agregaría la función toJSON en todos los miembros descendientes de cualquier objeto dado, tratando con referencias circulares y tal. Sin embargo, suponiendo Javascript de un solo hilo (sin Web Workers), este método debería funcionar y no producir efectos secundarios no deseados.

Se debe agregar una función similar al prototipo de Array para anular Object devolviendo una matriz y no un objeto. Otra opción sería adjuntar una sola y dejar que devuelva selectivamente una matriz o un objeto dependiendo de la naturaleza de los objetos, pero probablemente sea más lenta.

function JSONstringifyWithFuncs(obj) { 
    Object.prototype.toJSON = function() { 
    var sobj = {}, i; 
    for (i in this) 
     if (this.hasOwnProperty(i)) 
     sobj[i] = typeof this[i] == 'function' ? 
      this[i].toString() : this[i]; 

    return sobj; 
    }; 
    Array.prototype.toJSON = function() { 
     var sarr = [], i; 
     for (i = 0 ; i < this.length; i++) 
      sarr.push(typeof this[i] == 'function' ? this[i].toString() : this[i]); 

     return sarr; 
    }; 

    var str = JSON.stringify(obj); 

    delete Object.prototype.toJSON; 
    delete Array.prototype.toJSON; 

    return str; 
} 

http://jsbin.com/yerumateno/2/edit

+1

Genial, excepto que las matrices ya no se serializan como matrices. – Adaptabi

+3

¿Cómo sería la función de análisis? Todas las funciones están en cadenas, por lo que en el análisis debemos convertirlas nuevamente en funciones. – Justin

0

Algo como esto ...

(function(o) { 
    var s = ""; 
    for (var x in o) { 
     s += x + ": " + o[x] + "\n"; 
    } 
    return s; 
})(obj) 

Nota: esta es una expresión. Devuelve una representación de cadena del objeto que se pasa como un argumento (en mi ejemplo, estoy pasando el en una variable llamada obj).

También puede reemplazar el método toString de prototipo del objeto:

Object.prototype.toString = function() { 
    // define what string you want to return when toString is called on objects 
} 
1

Es imposible sin la ayuda del propio objeto. Por ejemplo, ¿cómo serializarías el resultado de esta expresión?

 
(function() { 
    var x; 
    return { 
     get: function() { return x; }, 
     set: function (y) { return x = y; } 
    }; 
})(); 

Si usted acaba de tomar el texto de la función, a continuación, al deserializar, x hará referencia a la variable global, no una en un cierre. Además, si su función se cierra sobre el estado del navegador (como una referencia a un div), tendría que pensar en lo que quiere decir.

Puede, por supuesto, escribir sus propios métodos específicos para objetos individuales que codifican qué semántica quiere que tengan referencias a otros objetos.

5

Puede utilizar JSON.stringify con un replacer como:

JSON.stringify({ 
    color: 'red', 
    doSomething: function (arg) { 
     alert('Do someting called with ' + arg); 
    } 
}, function(key, val) { 
     return (typeof val === 'function') ? '' + val : val; 
}); 
+2

Terminé usando 'JSON.stringify (myObject, function (key, val) {return (typeof val === 'function')? '[Function]': val;}, 4);' y produce muy buenos resultados . –

Cuestiones relacionadas