Vorrei memorizzare un oggetto JavaScript in HTML5 localStorage
, ma il mio oggetto viene apparentemente convertito in una stringa.
Posso memorizzare e recuperare tipi JavaScript primitivi e array usando localStorage
, ma gli oggetti non sembrano funzionare. Dovrebbero?
Ecco il mio codice:
var testObject = { 'one': 1, 'two': 2, 'three': 3 };
console.log('typeof testObject: ' + typeof testObject);
console.log('testObject properties:');
for (var prop in testObject) {
console.log(' ' + prop + ': ' + testObject[prop]);
}
// Put the object into storage
localStorage.setItem('testObject', testObject);
// Retrieve the object from storage
var retrievedObject = localStorage.getItem('testObject');
console.log('typeof retrievedObject: ' + typeof retrievedObject);
console.log('Value of retrievedObject: ' + retrievedObject);
L'output della console è
-- lingua: lang-none -->
typeof testObject: object
testObject properties:
one: 1
two: 2
three: 3
typeof retrievedObject: string
Value of retrievedObject: [object Object]
Mi sembra che il metodo setItem
stia convertendo l'input in una stringa prima di memorizzarlo.
Vedo questo comportamento in Safari, Chrome e Firefox, quindi presumo che sia una mia incomprensione della specifica HTML5 Web Storage, non un bug o una limitazione specifica del browser.
Ho cercato di dare un senso all'algoritmo del clone strutturato descritto in http://www.w3.org/TR/html5/infrastructure.html. Non capisco bene cosa dice, ma forse il mio problema ha a che fare con le proprietà del mio oggetto che non sono enumerabili (???)
C'è un facile workaround?
Aggiornamento: il W3C alla fine ha cambiato idea sulla specifica del clone strutturato, e ha deciso di cambiare la specifica per adattarla alle implementazioni. Vedere https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111. Quindi questa domanda non è più valida al 100%, ma le risposte possono ancora essere interessanti.
Guardando la documentazione di Apple, Mozilla e Mozilla ancora, la funzionalità sembra essere limitata a gestire solo coppie chiave/valore di stringhe.
Un workaround può essere quello di stringificare il vostro oggetto prima di memorizzarlo, e successivamente analizzarlo quando lo recuperate:
var testObject = { 'one': 1, 'two': 2, 'three': 3 };
// Put the object into storage
localStorage.setItem('testObject', JSON.stringify(testObject));
// Retrieve the object from storage
var retrievedObject = localStorage.getItem('testObject');
console.log('retrievedObject: ', JSON.parse(retrievedObject));
Un piccolo miglioramento su una variante:
Storage.prototype.setObject = function(key, value) {
this.setItem(key, JSON.stringify(value));
}
Storage.prototype.getObject = function(key) {
var value = this.getItem(key);
return value && JSON.parse(value);
}
A causa del short-circuit evaluation, getObject()
restituirà immediatamente un null
se key
non è in Storage. Inoltre non lancerà un'eccezione SyntaxError
se value
è ""
(la stringa vuota; JSON.parse()
non può gestirla).
Potreste trovare utile estendere l'oggetto Storage con questi comodi metodi:
Storage.prototype.setObject = function(key, value) {
this.setItem(key, JSON.stringify(value));
}
Storage.prototype.getObject = function(key) {
return JSON.parse(this.getItem(key));
}
In questo modo si ottiene la funzionalità che si voleva veramente anche se sotto l'API supporta solo le stringhe.