Me gustaría almacenar un objeto JavaScript en HTML5 localStorage
, pero mi objeto aparentemente se convierte en una cadena.
Puedo almacenar y recuperar tipos primitivos de JavaScript y matrices utilizando localStorage
, pero los objetos no parecen funcionar. ¿Deberían?
Este es mi código:
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);
La salida de la consola es
idioma: lang-none -->
typeof testObject: object
testObject properties:
one: 1
two: 2
three: 3
typeof retrievedObject: string
Value of retrievedObject: [object Object]
Me parece que el método setItem
está convirtiendo la entrada en una cadena antes de almacenarla.
Veo este comportamiento en Safari, Chrome y Firefox, así que asumo que es mi malentendido de la especificación HTML5 Web Storage, no un error o limitación específica del navegador.
He intentado dar sentido al algoritmo de clon estructurado descrito en http://www.w3.org/TR/html5/infrastructure.html. No entiendo del todo lo que dice, pero tal vez mi problema tiene que ver con que las propiedades de mi objeto no son enumerables (???)
¿Hay alguna solución fácil?
Actualización: El W3C finalmente cambió de opinión sobre la especificación de clones estructurados, y decidió cambiar la especificación para que coincida con las implementaciones. Véase https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111. Así que esta pregunta ya no es 100% válida, pero las respuestas todavía pueden ser de interés.
Mirando la documentación de Apple, Mozilla y Mozilla otra vez, la funcionalidad parece estar limitada a manejar sólo pares de cadena clave/valor.
Una solución puede ser stringificar su objeto antes de almacenarlo, y luego analizarlo cuando lo recupere:
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));
Una pequeña mejora de 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);
}
Debido a la evaluación de cortocircuito, getObject()
devolverá inmediatamente null
si key
no está en Storage. Tampoco lanzará una excepción SyntaxError
si value
es ""
(la cadena vacía; JSON.parse()
no puede manejar eso).
Puede resultar útil ampliar el objeto Storage con estos prácticos métodos:
Storage.prototype.setObject = function(key, value) {
this.setItem(key, JSON.stringify(value));
}
Storage.prototype.getObject = function(key) {
return JSON.parse(this.getItem(key));
}
De este modo, obtendrás la funcionalidad que realmente querías aunque en el fondo la API sólo admita cadenas.