2010-09-10 13 views
18

Sto cercando una soluzione per serializzare (e non serializzare) oggetti Javascript su una stringa tra i vari browser, inclusi i membri dell'oggetto che si presentano come funzioni. Un oggetto tipico sarà simile a questa:Javascript: stringify oggetto (compresi i membri della funzione type)

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

doSomething() conterrà solo le variabili locali (non c'è bisogno di serializzare anche il contesto di chiamata!).

JSON.stringify() ignorerà il membro 'doSomething' perché è una funzione. Ho saputo che il metodo toSource() farà ciò che voglio ma è FF specifico.

+1

mi limiterò a lasciare un commento, perché non sto offrendo una soluzione completa. Una cosa che può essere d'aiuto è che puoi stringificare una funzione con una chiamata a 'toString()'. http://jsfiddle.net/HFMaz/ Non sono sicuro del supporto cross-browser. – user113716

+1

viene chiesto regolarmente ma non riesco a trovare nulla di rilevante: \ perché è necessario serializzare la funzione in ogni caso? forse c'è un modo migliore per organizzare il tuo codice? – lincolnk

+0

Questo è per il progetto WYSIWYG. Ogni oggetto Javascript (con metodi) definisce il comportamento dei componenti della pagina. Il contenuto della pagina (incluso il comportamento JS) deve essere salvato lato server, quindi serializzato. –

risposta

5

Un modo rapido e sporco sarebbe stato così:

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; 

}; 

Ovviamente questo influenzerà la serializzazione di ogni oggetto nel codice, e potrebbe inciampare Codice niave utilizzando filtrati for in loop. Il modo "corretto" sarebbe quello di scrivere una funzione ricorsiva che aggiungerebbe la funzione toJSON a tutti i membri discendenti di un dato oggetto, occupandosi di riferimenti circolari e simili. Tuttavia, assumendo Javascript con thread singolo (senza Web Workers), questo metodo dovrebbe funzionare e non produrre effetti collaterali indesiderati.

Una funzione simile deve essere aggiunta al prototipo di Array per sovrascrivere l'oggetto restituendo un array e non un oggetto. Un'altra opzione sarebbe quella di allegare una singola e lasciare che restituisca una matrice o un oggetto in modo selettivo a seconda della natura degli oggetti, ma probabilmente sarebbe più 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

Grande, tranne che gli array non sono più serializzati come array. – Adaptabi

+3

Come si presenta la funzione di analisi? Tutte le funzioni sono in stringhe quindi, in analisi, è necessario convertirle nuovamente in funzioni. – Justin

0

qualcosa di simile ...

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

Nota: questo è espressione. Restituisce una rappresentazione di stringa dell'oggetto che viene passato come argomento (nel mio esempio, sto passando il in una variabile denominata obj).

È inoltre possibile eseguire l'override del metodo toString di prototipi dell'oggetto:

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

E 'impossibile senza l'aiuto dell'oggetto stesso. Ad esempio, come serializzeresti il ​​risultato di questa espressione?

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

Se si prende il testo della funzione, poi, quando si deserializzare, x farà riferimento alla variabile globale, non uno in una chiusura. Inoltre, se la tua funzione si chiude sullo stato del browser (come un riferimento a un div), dovresti pensare a cosa vuoi che significhi.

È possibile, naturalmente, scrivere i propri metodi specifici per singoli oggetti che codificano la semantica di cui si desidera fare riferimento ad altri oggetti.

5

È possibile utilizzare JSON.stringify con una replacer come:

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

Ho finito con l'uso di 'JSON.stringify (myObject, function (key, val) {return (typeof val === 'function')? '[Function]': val;}, 4);' e risulta veramente bello . –

Problemi correlati