Frage Speichern von Objekten in HTML5 localStorage


Ich möchte ein JavaScript-Objekt in HTML5 speichern localStorage, aber mein Objekt wird anscheinend in eine Zeichenkette umgewandelt.

Ich kann primitive JavaScript-Typen und -Arrays mithilfe von speichern und abrufen localStorage, aber Objekte scheinen nicht zu funktionieren. Sollten Sie?

Hier ist mein Code:

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);

Die Konsolenausgabe ist

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

Es sieht für mich wie die aus setItem Die Methode konvertiert die Eingabe in eine Zeichenfolge, bevor sie gespeichert wird.

Ich sehe dieses Verhalten in Safari, Chrome und Firefox, also nehme ich an, dass es mein Missverständnis ist HTML5-Webspeicher Spezifikation, kein Browser-spezifischer Fehler oder Einschränkung.

Ich habe versucht, einen Sinn für die strukturierter Klon Algorithmus beschrieben in http://www.w3.org/TR/html5/infrastructure.html. Ich verstehe nicht ganz, was es sagt, aber vielleicht hat mein Problem damit zu tun, dass die Eigenschaften meines Objekts nicht aufzählbar sind (???)

Gibt es einen einfachen Workaround?


Update: Das W3C änderte schließlich seine Meinung über die Strukturierte-Klon-Spezifikation und entschied, die Spezifikation so zu ändern, dass sie mit den Implementierungen übereinstimmte. Sehen https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111. Diese Frage ist also nicht mehr zu 100% gültig, aber die Antworten mögen noch von Interesse sein.


2051
2018-01-06 04:05


Ursprung


Antworten:


Mit Blick auf die Apfel, Mozilla und Microsoft Dokumentation, die Funktionalität scheint beschränkt zu sein, nur String-Schlüssel / Wert-Paare zu behandeln.

Ein Workaround kann sein stringifizieren Ihr Objekt, bevor Sie es speichern und später analysieren, wenn Sie es abrufen:

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



Eine kleine Verbesserung auf a 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);
}

Durch Kurzschlussauswertung, getObject() werden sofort Rückkehr null ob key ist nicht im Speicher. Es wird auch nicht geworfen SyntaxError Ausnahme wenn value ist "" (die leere Zeichenfolge; JSON.parse() kann das nicht handhaben).


562
2018-06-30 06:45



Es könnte nützlich sein, das Storage-Objekt mit diesen praktischen Methoden zu erweitern:

Storage.prototype.setObject = function(key, value) {
    this.setItem(key, JSON.stringify(value));
}

Storage.prototype.getObject = function(key) {
    return JSON.parse(this.getItem(key));
}

Auf diese Weise erhalten Sie die Funktionalität, die Sie wirklich wollten, obwohl unterhalb der API nur Strings unterstützt.


195
2018-01-06 04:42



Die Erweiterung des Storage-Objekts ist eine großartige Lösung. Für meine API habe ich eine Fassade für localStorage erstellt und dann überprüft, ob es ein Objekt ist oder nicht.

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



Es gibt eine großartige Bibliothek, die viele Lösungen umschließt, so dass sie sogar ältere Browser unterstützt jSpeicher

Sie können ein Objekt festlegen

$.jStorage.set(key, value)

Und es einfach abrufen

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

52
2017-08-23 03:52



Stringify löst nicht alle Probleme

Es scheint, dass die Antworten hier nicht alle Typen abdecken, die in JavaScript möglich sind. Hier finden Sie einige kurze Beispiele, wie Sie mit ihnen richtig umgehen:

//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"

Ich empfehle nicht Funktionen zu speichern, weil eval() Das Böse kann zu Sicherheit, Optimierung und Debugging führen.         Im Algemeinen, eval() sollte niemals in JavaScript-Code verwendet werden.

Private Mitglieder

Das Problem mit der Verwendung JSON.stringify()zum Speichern von Objekten ist, dass diese Funktion keine privaten Mitglieder serialisieren kann. Dieses Problem kann gelöst werden, indem man das .toString() Methode (die implizit beim Speichern von Daten im Webspeicher aufgerufen wird):

//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);

Zirkelverweise

Ein weiteres Problem stringify kann nicht mit zirkulären Referenzen umgehen:

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

In diesem Beispiel JSON.stringify() wirf ein TypeError  "Konvertieren der kreisförmigen Struktur in JSON".         Wenn zirkuläre Referenzen gespeichert werden sollen, wird der zweite Parameter von JSON.stringify() könnte verwendet werden:

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;
    }
});

Die Suche nach einer effizienten Lösung zum Speichern zirkulärer Referenzen hängt jedoch stark von den Aufgaben ab, die gelöst werden müssen, und das Wiederherstellen solcher Daten ist ebenfalls nicht trivial.

Es gibt bereits einige Fragen zu SO, die sich mit diesem Problem befassen: Zeichne ein JavaScript-Objekt mit Zirkelverweis (konvertiere nach JSON)


50
2017-11-19 09:51



JSON-Objekte für lokalen Speicher verwenden:

//EINSTELLEN

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

//BEKOMMEN

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

// Iteration aller lokalen Speicherschlüssel und Werte

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

// LÖSCHEN

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

29
2017-11-20 07:06



Theoretisch ist es möglich, Objekte mit Funktionen zu speichern:

function store (a)
{
  var c = {f: {}, d: {}};
  for (var k in a)
  {
    if (a.hasOwnProperty(k) && typeof a[k] === 'function')
    {
      c.f[k] = encodeURIComponent(a[k]);
    }
  }

  c.d = a;
  var data = JSON.stringify(c);
  window.localStorage.setItem('CODE', data);
}

function restore ()
{
  var data = window.localStorage.getItem('CODE');
  data = JSON.parse(data);
  var b = data.d;

  for (var k in data.f)
  {
    if (data.f.hasOwnProperty(k))
    {
      b[k] = eval("(" + decodeURIComponent(data.f[k]) + ")");
    }
  }

  return b;
}

Die Serialisierung / Deserialisierung von Funktionen ist jedoch unzuverlässig es ist implementierungsabhängig.


27
2018-04-05 21:20



Sie könnten auch den Standardspeicher überschreiben setItem(key,value) und getItem(key) Methoden, um Objekte / Arrays wie jeden anderen Datentyp zu behandeln. Auf diese Weise können Sie einfach anrufen localStorage.setItem(key,value) und localStorage.getItem(key) wie du normalerweise würdest.

Ich habe das nicht ausgiebig getestet, aber es scheint für ein kleines Projekt, mit dem ich getüftelt habe, problemlos zu funktionieren.

Storage.prototype._setItem = Storage.prototype.setItem;
Storage.prototype.setItem = function(key, value)
{
  this._setItem(key, JSON.stringify(value));
}

Storage.prototype._getItem = Storage.prototype.getItem;
Storage.prototype.getItem = function(key)
{  
  try
  {
    return JSON.parse(this._getItem(key));
  }
  catch(e)
  {
    return this._getItem(key);
  }
}

22
2018-04-26 13:00



Ich kam zu diesem Post, nachdem ich auf einen anderen Post geklickt hatte, der als Duplikat geschlossen wurde - mit dem Titel "Wie speichere ich ein Array im lokalen Speicher?". Das ist in Ordnung, aber keiner der beiden Threads liefert tatsächlich eine vollständige Antwort darauf, wie Sie ein Array in localStorage verwalten können - jedoch habe ich es geschafft, eine Lösung auf Basis der in beiden Threads enthaltenen Informationen zu erstellen.

Wenn also jemand anderes in der Lage sein möchte, Elemente in einem Array zu pushen / verschieben / verschieben, und sie möchten, dass das Array in localStorage oder in der Tat in sessionStorage gespeichert wird, dann gehst du:

Storage.prototype.getArray = function(arrayName) {
  var thisArray = [];
  var fetchArrayObject = this.getItem(arrayName);
  if (typeof fetchArrayObject !== 'undefined') {
    if (fetchArrayObject !== null) { thisArray = JSON.parse(fetchArrayObject); }
  }
  return thisArray;
}

Storage.prototype.pushArrayItem = function(arrayName,arrayItem) {
  var existingArray = this.getArray(arrayName);
  existingArray.push(arrayItem);
  this.setItem(arrayName,JSON.stringify(existingArray));
}

Storage.prototype.popArrayItem = function(arrayName) {
  var arrayItem = {};
  var existingArray = this.getArray(arrayName);
  if (existingArray.length > 0) {
    arrayItem = existingArray.pop();
    this.setItem(arrayName,JSON.stringify(existingArray));
  }
  return arrayItem;
}

Storage.prototype.shiftArrayItem = function(arrayName) {
  var arrayItem = {};
  var existingArray = this.getArray(arrayName);
  if (existingArray.length > 0) {
    arrayItem = existingArray.shift();
    this.setItem(arrayName,JSON.stringify(existingArray));
  }
  return arrayItem;
}

Storage.prototype.unshiftArrayItem = function(arrayName,arrayItem) {
  var existingArray = this.getArray(arrayName);
  existingArray.unshift(arrayItem);
  this.setItem(arrayName,JSON.stringify(existingArray));
}

Storage.prototype.deleteArray = function(arrayName) {
  this.removeItem(arrayName);
}

Beispielverwendung - Speichern einfacher Strings im localStorage-Array:

localStorage.pushArrayItem('myArray','item one');
localStorage.pushArrayItem('myArray','item two');

Beispielverwendung - Speichern von Objekten im sessionStorage-Array:

var item1 = {}; item1.name = 'fred'; item1.age = 48;
sessionStorage.pushArrayItem('myArray',item1);

var item2 = {}; item2.name = 'dave'; item2.age = 22;
sessionStorage.pushArrayItem('myArray',item2);

übliche Methoden zum Bearbeiten von Arrays:

.pushArrayItem(arrayName,arrayItem); -> adds an element onto end of named array
.unshiftArrayItem(arrayName,arrayItem); -> adds an element onto front of named array
.popArrayItem(arrayName); -> removes & returns last array element
.shiftArrayItem(arrayName); -> removes & returns first array element
.getArray(arrayName); -> returns entire array
.deleteArray(arrayName); -> removes entire array from storage

19
2018-05-07 11:35