Pregunta Almacenamiento de objetos en HTML5 localStorage


Me gustaría almacenar un objeto de JavaScript en HTML5 localStorage, pero mi objeto aparentemente se está convirtiendo en una cadena.

Puedo almacenar y recuperar tipos y matrices de JavaScript primitivos usando localStorage, pero los objetos no parecen funcionar. ¿Deberían ellos?

Aquí está 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

typeof testObject: object
testObject properties:
  one: 1
  two: 2
  three: 3
typeof retrievedObject: string
Value of retrievedObject: [object Object]

Me parece como el setItem método es convertir la entrada a una cadena antes de almacenarla.

Veo este comportamiento en Safari, Chrome y Firefox, así que supongo que es mi incomprensión de la Almacenamiento web HTML5 especificaciones, no un error o limitación específica del navegador.

Intenté darle sentido a la clon estructurado algoritmo descrito en http://www.w3.org/TR/html5/infrastructure.html. No entiendo completamente lo que dice, pero tal vez mi problema tiene que ver con que las propiedades de mi objeto no sean enumerables (???)

¿Hay una solución fácil?


Actualización: El W3C finalmente cambió de opinión sobre la especificación de clonación estructurada y decidió cambiar la especificación para que coincida con las implementaciones. Ver https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111. Entonces esta pregunta ya no es 100% válida, pero las respuestas aún pueden ser de interés.


2051
2018-01-06 04:05


origen


Respuestas:


Mirando a la manzana, Mozilla y Microsoft documentación, la funcionalidad parece estar limitada para manejar solo pares clave / valor de cadena.

Una solución alternativa puede ser stringify 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));

2650
2018-01-06 04:25



Una pequeña mejora en un 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);
}

Porque evaluación de cortocircuito, getObject() será inmediatamente regreso null Si key no está en Almacenamiento. Tampoco arrojará un SyntaxError excepción si value es "" (la cadena vacía; JSON.parse() no puede manejar eso).


562
2018-06-30 06:45



Puede que le resulte útil ampliar el objeto de almacenamiento 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 esta manera obtienes la funcionalidad que realmente querías, aunque debajo de la API solo se admiten cadenas.


195
2018-01-06 04:42



La ampliación del objeto de almacenamiento es una solución increíble. Para mi API, he creado una fachada para localStorage y luego verifico si es un objeto o no mientras configuro y obtengo.

var data = {
  set: function(key, value) {
    if (!key || !value) {return;}

    if (typeof value === "object") {
      value = JSON.stringify(value);
    }
    localStorage.setItem(key, value);
  },
  get: function(key) {
    var value = localStorage.getItem(key);

    if (!value) {return;}

    // assume it is an object that has been stringified
    if (value[0] === "{") {
      value = JSON.parse(value);
    }

    return value;
  }
}

64
2018-01-21 18:29



Hay una gran biblioteca que envuelve muchas soluciones, por lo que incluso admite navegadores antiguos llamados jStorage

Puedes establecer un objeto

$.jStorage.set(key, value)

Y recuperarlo fácilmente

value = $.jStorage.get(key)
value = $.jStorage.get(key, "default value")

52
2017-08-23 03:52



Stringify no resuelve todos los problemas

Parece que las respuestas aquí no cubren todos los tipos que son posibles en JavaScript, así que aquí hay algunos ejemplos cortos sobre cómo tratarlos correctamente:

//Objects and Arrays:
    var obj = {key: "value"};
    localStorage.object = JSON.stringify(obj);  //Will ignore private members
    obj = JSON.parse(localStorage.object);
//Boolean:
    var bool = false;
    localStorage.bool = bool;
    bool = (localStorage.bool === "true");
//Numbers:
    var num = 42;
    localStorage.num = num;
    num = +localStorage.num;    //short for "num = parseFloat(localStorage.num);"
//Dates:
    var date = Date.now();
    localStorage.date = date;
    date = new Date(parseInt(localStorage.date));
//Regular expressions:
    var regex = /^No\.[\d]*$/i;     //usage example: "No.42".match(regex);
    localStorage.regex = regex;
    var components = localStorage.regex.match("^/(.*)/([a-z]*)$");
    regex = new RegExp(components[1], components[2]);
//Functions (not recommended):
    function func(){}
    localStorage.func = func;
    eval( localStorage.func );      //recreates the function with the name "func"

no lo recomiendo para almacenar funciones porque eval() es malo puede conducir a problemas con respecto a la seguridad, la optimización y la depuración.         En general, eval() nunca debe usarse en código JavaScript.

Miembros privados

El problema con el uso JSON.stringify()para almacenar objetos es que esta función no puede serializar miembros privados. Este problema se puede resolver sobrescribiendo el .toString() método (que se llama implícitamente cuando se almacenan datos en el almacenamiento web):

//Object with private and public members:
    function MyClass(privateContent, publicContent){
        var privateMember = privateContent || "defaultPrivateValue";
        this.publicMember = publicContent  || "defaultPublicValue";

        this.toString = function(){
            return '{"private": "' + privateMember + '", "public": "' + this.publicMember + '"}';
        };
    }
    MyClass.fromString = function(serialisedString){
        var properties = JSON.parse(serialisedString || "{}");
        return new MyClass( properties.private, properties.public );
    };
//Storing:
    var obj = new MyClass("invisible", "visible");
    localStorage.object = obj;
//Loading:
    obj = MyClass.fromString(localStorage.object);

Referencias circulares

Otro problema stringify no se puede tratar con referencias circulares:

var obj = {};
obj["circular"] = obj;
localStorage.object = JSON.stringify(obj);  //Fails

En este ejemplo, JSON.stringify() arrojará un TypeError  "Convertir estructura circular a JSON".         Si el almacenamiento de referencias circulares debe ser compatible, el segundo parámetro de JSON.stringify() podría ser utilizado:

var obj = {id: 1, sub: {}};
obj.sub["circular"] = obj;
localStorage.object = JSON.stringify( obj, function( key, value) {
    if( key == 'circular') {
        return "$ref"+value.id+"$";
    } else {
        return value;
    }
});

Sin embargo, encontrar una solución eficiente para almacenar referencias circulares depende en gran medida de las tareas que deben resolverse, y la restauración de dichos datos tampoco es trivial.

Ya hay algunas preguntas sobre SO que se ocupan de este problema: Stringify (convertir a JSON) un objeto JavaScript con referencia circular


50
2017-11-19 09:51



Usando objetos JSON para almacenamiento local:

//CONJUNTO

var m={name:'Hero',Title:'developer'};
localStorage.setItem('us', JSON.stringify(m));

//OBTENER

var gm =JSON.parse(localStorage.getItem('us'));
console.log(gm.name);

// Iteración de todas las claves y valores de almacenamiento local

for (var i = 0, len = localStorage.length; i < len; ++i) {
  console.log(localStorage.getItem(localStorage.key(i)));
}

// BORRAR

localStorage.removeItem('us');
delete window.localStorage["us"];

29
2017-11-20 07:06