Existe-t-il une possibilité d'avoir les fonctions JSON.stringify preserve?

Prenez cet objet:

x = { "key1": "xxx", "key2": function(){return this.key1} } 

Si je fais ceci:

 y = JSON.parse( JSON.stringify(x) ); 

Ensuite, vous retournerez { "key1": "xxx" } . Existe-t-il une possibilité de transférer des fonctions via stringify? La création d'un objet avec des fonctions attachées est possible avec le "ye goode olde eval ()", mais qu'est-ce qu'il y a à l'emballer?

Vous ne pouvez pas emballer des fonctions car les données qu'elles ferment ne sont pas visibles pour un sérialiseur. Même Mozilla n'est pas capable de conditionner correctement les fermetures.

Votre meilleur pari, c'est utiliser un réviver et un remplacement.

http://developer.yahoo.com/yui/examples/json/json_freeze_thaw.html

La fonction reviver passée à JSON.parse est appliquée à toutes les clés: valeur des paires dans l'objet parsed brut des touches les plus profondes au plus haut niveau. Dans notre cas, cela signifie que le nom et les propriétés découvertes passeront par le réviver, puis l'objet contenant ces clés sera transmis.

J'ai rencontré le même problème: il y avait un autre message semblable à celui que vous avez trouvé dans la fonction json-stringify . Les suivantes peuvent vous être utiles:

 var JSONfn; if (!JSONfn) { JSONfn = {}; } (function () { JSONfn.stringify = function(obj) { return JSON.stringify(obj,function(key, value){ return (typeof value === 'function' ) ? value.toString() : value; }); } JSONfn.parse = function(str) { return JSON.parse(str,function(key, value){ if(typeof value != 'string') return value; return ( value.substring(0,8) == 'function') ? eval('('+value+')') : value; }); } }()); 

Extrait de code tiré de JSONfn.js de Vadim Kiryukhin ou voir la documentation à la page d'accueil

Techniquement, ce n'est pas JSON, je ne peux pas imaginer pourquoi voudriez-vous le faire, mais essayez le hack suivant:

 x.key2 = x.key2.toString(); JSON.stringify(x) //"{"key1":"xxx","key2":"function (){return this.key1}"}" 

Bien sûr, la première ligne peut être automatisée en itérant de façon récursive sur l'objet. L'opération inversée est plus difficile: la fonction n'est qu'une chaîne, eval fonctionne, mais vous devez deviner si une clé donnée contient un code de fonction stringifié ou non.

À ma connaissance, il n'existe pas de bibliothèques de sérialisation qui persistent dans toutes les langues. La sérialisation est ce que l'on fait pour préserver les données. La compilation est ce que l'on fait pour préserver les fonctions.

Oui, vous pouvez le faire avec le plugin JSONfn.

Jetez un oeil à http://www.eslinstructor.net/jsonfn/

C'est exactement ce que vous recherchez.

Il semble que les personnes qui débarquent ici traitent des structures qui seraient valides JSON sinon pour le fait qu'elles contiennent des fonctions. Alors, comment pouvons-nous gérer la chaîne de ces structures?

J'ai rencontré le problème lors de l'écriture d'un script pour modifier les configurations RequireJS. C'est ainsi que je l'ai fait. Tout d'abord, il y a un peu plus de code qui permet de s'assurer que l'espace réservé utilisé en interne ( ">>>F<<<" ) n'apparaît pas comme une valeur dans la configuration RequireJS. Très peu probable que cela se produise, mais mieux que désolé. La configuration d'entrée est lue comme un objet JavaScript, qui peut contenir des tableaux, des valeurs atomiques, d'autres Object et fonctions. Il serait simplement stringible en tant que JSON si les fonctions n'étaient pas présentes. Cette configuration est l'objet config dans le code qui suit:

 // Holds functions we encounter. var functions = []; var placeholder = ">>>F<<<"; // This handler just records a function object in `functions` and returns the // placeholder as the value to insert into the JSON structure. function handler(key, value) { if (value instanceof Function) { functions.push(value); return placeholder; } return value; } // We stringify, using our custom handler. var pre = JSON.stringify(config, handler, 4); // Then we replace the placeholders in order they were encountered, with // the functions we've recorded. var post = pre.replace(new RegExp('"' + placeholder + '"', 'g'), functions.shift.bind(functions)); 

La variable de post contient la valeur finale. Ce code repose sur le fait que l'ordre dans lequel le handler est appelé est identique à l'ordre des différentes données dans le JSON final. J'ai vérifié la 5ème édition ECMAScript, qui définit l'algorithme de stringification et ne peut pas trouver un cas où il y aurait un problème de commande. Si cet algorithme devait changer dans une future édition, le correctif serait d'utiliser des porteurs uniques pour la fonction et de les utiliser pour renvoyer les fonctions qui seraient stockées dans un tableau associatif cartographiant des espaces réservés uniques aux fonctions.

Le moyen vilain mais efficace serait simplement:

 Function.prototype.toJSON = function() { return this.toString(); } 

Bien que votre vrai problème (en dehors de la modification du prototype de Function ) soit désérialisation sans l'utilisation d' eval .

Il est tout à fait possible de créer des fonctions à partir de chaîne sans eval()

 var obj = {a:function(a,b){ return a+b; }}; var serialized = JSON.stringify(obj, function(k,v){ //special treatment for function types if(typeof v === "function") return v.toString();//we save the function as string return v; }); /*output: "{"a":"function (a,b){\n return a+b;\n }"}" */ 

Maintenant une magie pour transformer la chaîne en fonction avec cette fonction

 var compileFunction = function(str){ //find parameters var pstart = str.indexOf('('), pend = str.indexOf(')'); var params = str.substring(pstart+1, pend); params = params.trim(); //find function body var bstart = str.indexOf('{'), bend = str.lastIndexOf('}'); var str = str.substring(bstart+1, bend); return Function(params, str); } 

Utilisez JSON.parse avec reviver

 var revivedObj = JSON.parse(serialized, function(k,v){ // there is probably a better way to determ if a value is a function string if(typeof v === "string" && v.indexOf("function") !== -1) return compileFunction(v); return v; }); //output: revivedObj.a function anonymous(a,b /**/) { return a+b; } revivedObj.a(1,2) 3 

J'avais presque le même problème, j'ai écrit ceci https://github.com/simone-sanfratello/jsfy

Peut-être peut-être aider

C'est ce que j'ai fait https://gist.github.com/Lepozepo/3275d686bc56e4fb5d11d27ef330a8ed

 function stringifyWithFunctions(object) { return JSON.stringify(object, (key, val) => { if (typeof val === 'function') { return `(${val})`; // make it a string, surround it by parenthesis to ensure we can revive it as an anonymous function } return val; }); }; function parseWithFunctions(obj) { return JSON.parse(obj, (k, v) => { if (typeof v === 'string' && v.indexOf('function') >= 0) { return eval(v); } return v; }); };