Ich möchte ein JavaScript-Objekt in HTML5 speichern localStorage
, aber mein Objekt wird anscheinend in eine Zeichenfolge konvertiert.
Ich kann primitive JavaScript-Typen und -Arrays mit 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]
Für mich sieht es so aus, als würde die setItem
Methode die Eingabe vor dem Speichern in einen String konvertieren.
Ich sehe dieses Verhalten in Safari, Chrome und Firefox, daher gehe ich davon aus, dass es mein Missverständnis der HTML5-Webspeicher- Spezifikation ist, kein browserspezifischer Fehler oder eine Einschränkung.
Ich habe versucht, den in http://www.w3.org/TR/html5/infrastructure.html beschriebenen strukturierten Klonalgorithmus zu verstehen . 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 eine einfache Problemumgehung?
Update: Das W3C änderte schließlich seine Meinung über die Struktur-Klon-Spezifikation und beschloss, die Spezifikation an die Implementierungen anzupassen. Siehe https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111 . Diese Frage ist also nicht mehr zu 100% gültig, aber die Antworten könnten dennoch von Interesse sein.
quelle
Antworten:
Wenn man sich die Dokumentation von Apple , Mozilla und Mozilla noch einmal ansieht, scheint die Funktionalität darauf beschränkt zu sein, nur Zeichenfolgenschlüssel / Wert-Paare zu verarbeiten.
Eine Problemumgehung kann darin bestehen, Ihr Objekt vor dem Speichern zu stringifizieren und es später beim Abrufen zu analysieren:
quelle
JSON.stringify()
Zirkelverweisen und erweitert das referenzierte Objekt auf seinen vollständigen "Inhalt" (implizit stringifiziert) in dem Objekt, das wir stringifizieren. Siehe: stackoverflow.com/a/12659424/2044940Eine kleine Verbesserung gegenüber einer Variante :
Wegen der Kurzauswertung ,
getObject()
wird sofort zurückkehren ,null
wennkey
nicht Lager ist. Es wird auch keineSyntaxError
Ausnahme ausgelöst, wenn dies der Fallvalue
ist""
(die leere Zeichenfolge;JSON.parse()
kann damit nicht umgehen).quelle
var userObject = { userId: 24, name: 'Jack Bauer' };
Und um sielocalStorage.setObject('user', userObject);
festzulegen. Dann holen Sie sie aus dem Speicher zurück.userObject = localStorage.getObject('user');
Sie können sogar eine Reihe von Objekten speichern, wenn Sie möchten.key
nicht im lokalen Speicher ist,window.localStorage.getItem(key)
kehrtnull
- es ist nicht eine „Illegal Zugang“ Ausnahme auslösen - undJSON.parse(null)
kehrtnull
als auch - es ist nicht eine Ausnahme entweder werfen, weder in Chromium 21 noch pro IHM 5.1 Abschnitt 15.12.2 , weilString(null) === "null"
die als JSON-Literal interpretiert werden .""
(die leere Zeichenfolge) gespeichert hat . Da es typkonvertiert infalse
undJSON.parse("")
, was eineSyntaxError
Ausnahme auslösen würde , wird es nicht aufgerufen.Möglicherweise ist es hilfreich, das Speicherobjekt mit den folgenden praktischen Methoden zu erweitern:
Auf diese Weise erhalten Sie die Funktionalität, die Sie wirklich wollten, obwohl unter der API nur Zeichenfolgen unterstützt werden.
quelle
localStorage.setObject
.getObject()
löst eineSyntaxError
Ausnahme aus, wenn der gespeicherte Wert lautet""
, daJSON.parse()
dies nicht möglich ist. Siehe meine Bearbeitung von Gurias Antwort für Details.Das Erweitern des Speicherobjekts ist eine großartige Lösung. Für meine API habe ich eine Fassade für localStorage erstellt und dann beim Festlegen und Abrufen überprüft, ob es sich um ein Objekt handelt oder nicht.
quelle
data.set('username': 'ifedi', 'fullname': { firstname: 'Ifedi', lastname: 'Okonkwo'});
?Stringify löst nicht alle Probleme
Es scheint, dass die Antworten hier nicht alle Typen abdecken, die in JavaScript möglich sind. Hier sind einige kurze Beispiele, wie man richtig damit umgeht:
Ich empfehle nicht , Funktionen zu speichern, weil
eval()
dies zu Problemen in Bezug auf Sicherheit, Optimierung und Debugging führen kann. Im Allgemeineneval()
sollte niemals in JavaScript-Code verwendet werden.Private Mitglieder
Das Problem bei der Verwendung
JSON.stringify()
zum Speichern von Objekten besteht darin, dass diese Funktion private Mitglieder nicht serialisieren kann. Dieses Problem kann durch Überschreiben der.toString()
Methode behoben werden (die beim Speichern von Daten im Webspeicher implizit aufgerufen wird):Rundschreiben
Ein weiteres Problem, mit dem
stringify
man sich nicht befassen kann, sind Zirkelverweise:In diesem Beispiel
JSON.stringify()
wird eineTypeError
"Konvertieren einer kreisförmigen Struktur in JSON" ausgelöst . Wenn das Speichern von Zirkelverweisen unterstützt werden soll, kann der zweite Parameter vonJSON.stringify()
verwendet werden:Die Suche nach einer effizienten Lösung zum Speichern von Zirkelverweisen hängt jedoch stark von den zu lösenden Aufgaben ab, und das Wiederherstellen solcher Daten ist ebenfalls nicht trivial.
Es gibt bereits einige Fragen zu SO, die sich mit diesem Problem befassen : Stringifizieren (Konvertieren in JSON) eines JavaScript-Objekts mit Zirkelverweis
quelle
Es gibt eine großartige Bibliothek, die viele Lösungen umfasst und sogar ältere Browser namens jStorage unterstützt
Sie können ein Objekt festlegen
Und einfach abrufen
quelle
Theoretisch ist es möglich, Objekte mit Funktionen zu speichern:
Die Serialisierung / Deserialisierung von Funktionen ist jedoch unzuverlässig, da sie implementierungsabhängig ist .
quelle
c.f[k] = escape(a[k]);
den Unicode-Safec.f[k] = encodeURIComponent(a[k]);
undeval('b.' + k + ' = ' + unescape(data.f[k]));
durch ersetzenb[k] = eval("(" + decodeURIComponent(data.f[k]) + ")");
. Die Klammern sind erforderlich, da Ihre Funktion bei ordnungsgemäßer Serialisierung wahrscheinlich anonym ist, was nicht so ist wie eine gültige / Anweisung / (soeval()
) würdeSyntaxError
sonst eine Ausnahme auslösen).typeof
ist ein Operator , schreiben Sie es nicht so, als ob es eine Funktion wäre. Ersetzentypeof(a[k])
durchtypeof a[k]
.for
-in
wurde nicht nach eigenen Eigenschaften gefiltert. 3. Der Codestil, einschließlich der Referenzierung, war inkonsistent.the use and placement of white space, line terminators, and semicolons within the representation String is implementation-dependent.
ich keine funktionalen Unterschiede sehe.Note *in particular* that …
. Die Rückgabewertspezifikation beginnt jedoch mitAn implementation-dependent representation of the function is returned. This representation has the syntax of a FunctionDeclaration.
Der Rückgabewert kann seinfunction foo () {}
- unter der Annahme einer konformen Implementierung.Ich bin zu diesem Beitrag gekommen, nachdem ich auf einen anderen Beitrag gestoßen bin, der als Duplikat geschlossen wurde - mit dem Titel "Wie speichere ich ein Array in localstorage?". Was in Ordnung ist, außer dass keiner der Threads tatsächlich eine vollständige Antwort darauf gibt, wie Sie ein Array in localStorage verwalten können. Ich habe es jedoch geschafft, eine Lösung basierend auf den in beiden Threads enthaltenen Informationen zu erstellen.
Wenn also jemand anderes in der Lage sein möchte, Elemente innerhalb eines Arrays zu verschieben, zu verschieben oder zu verschieben, und dieses Array in localStorage oder in sessionStorage gespeichert werden soll, können Sie Folgendes tun:
Beispiel für die Verwendung - Speichern einfacher Zeichenfolgen im localStorage-Array:
Anwendungsbeispiel - Speichern von Objekten im sessionStorage-Array:
gängige Methoden zum Bearbeiten von Arrays:
quelle
Empfehlen Sie die Verwendung einer Abstraktionsbibliothek für viele der hier beschriebenen Funktionen sowie für eine bessere Kompatibilität. Viele Optionen:
quelle
Sie können localDataStorage verwenden Javascript-Datentypen (Array, Boolean, Date, Float, Integer, String und Object) transparent speichern. Es bietet außerdem eine einfache Datenverschleierung, komprimiert Zeichenfolgen automatisch, erleichtert die Abfrage nach Schlüssel (Name) sowie die Abfrage nach (Schlüssel) Wert und hilft, segmentierten gemeinsamen Speicher innerhalb derselben Domäne durch Präfixieren von Schlüsseln zu erzwingen.
[HAFTUNGSAUSSCHLUSS] Ich bin der Autor des Dienstprogramms [/ HAFTUNGSAUSSCHLUSS]
Beispiele:
Wie Sie sehen können, werden die primitiven Werte respektiert.
quelle
Eine andere Möglichkeit wäre, ein vorhandenes Plugin zu verwenden.
Zum Beispiel ist persisto ein Open Source-Projekt, das eine einfache Schnittstelle zu localStorage / sessionStorage bietet und die Persistenz für Formularfelder (Eingabe, Optionsfelder und Kontrollkästchen) automatisiert.
(Haftungsausschluss: Ich bin der Autor.)
quelle
localStroage
; exp:var lsh = new localStorageHelper(); lsh.setItem('bob', 'bill');
Enthält auch Ereignisse.Sie können ejson verwenden , um die Objekte als Zeichenfolgen zu speichern.
Hier ist mein localStorage-Wrapper mit ejson
https://github.com/UziTech/storage.js
Ich habe meinem Wrapper einige Typen hinzugefügt, einschließlich regulärer Ausdrücke und Funktionen
quelle
Ich habe einen weiteren minimalistischen Wrapper mit nur 20 Codezeilen erstellt, damit er so verwendet werden kann, wie er sollte:
https://github.com/zevero/simpleWebstorage
quelle
Für Typescript-Benutzer, die typisierte Eigenschaften festlegen und abrufen möchten:
Anwendungsbeispiel :
quelle
https://github.com/adrianmay/rhaboo ist eine localStorage-Zuckerschicht, mit der Sie Folgendes schreiben können:
JSON.stringify / parse wird nicht verwendet, da dies bei großen Objekten ungenau und langsam wäre. Stattdessen hat jeder Terminalwert einen eigenen localStorage-Eintrag.
Sie können wahrscheinlich vermuten, dass ich etwas mit Rhaboo zu tun haben könnte.
quelle
Hier eine erweiterte Version des von @danott geposteten Codes
Es wird auch implementieren Lösch Wert von localstorage und zeigt , wie man einen Getter und Setter - Schicht fügt so statt
localstorage.setItem(preview, true)
Du kannst schreiben
config.preview = true
Okay, hier waren wir:
Nun, Sie können den Aliase-Teil mit entfernen
.bind(...)
. Ich habe es jedoch nur eingefügt, da es wirklich gut ist, darüber Bescheid zu wissen. Ich habe Stunden gebraucht, um herauszufinden, warum ein einfachesget = localStorage.getItem;
nicht funktioniertquelle
Ich habe etwas gemacht, das die vorhandenen Speicherobjekte nicht zerstört, sondern einen Wrapper erstellt, damit Sie tun können, was Sie wollen. Das Ergebnis ist ein normales Objekt, keine Methoden, mit Zugriff wie jedes Objekt.
Das was ich gemacht habe.
Wenn Sie möchten, dass 1
localStorage
Eigenschaft magisch ist:Wenn Sie mehrere benötigen:
Alles , was Sie tun , um
prop
, oder die Objekte innerhalbstorage
automatisch in gespeichert werdenlocalStorage
. Du spielst immer mit einem echten Objekt, also kannst du solche Dinge tun:Und jedes neue Objekt in einem verfolgten Objekt wird automatisch verfolgt.
Der sehr große Nachteil: Es kommt darauf an,
Object.observe()
dass die Browserunterstützung sehr eingeschränkt ist. Und es sieht nicht so aus, als würde es bald für Firefox oder Edge kommen.quelle
Sie können den Schlüsselwert nicht ohne das Zeichenfolgenformat speichern .
LocalStorage unterstützt nur das String-Format für Schlüssel / Wert.
Aus diesem Grund sollten Sie Ihre Daten in Zeichenfolgen konvertieren, unabhängig davon, ob es sich um ein Array oder ein Objekt handelt .
Um Daten in localStorage zu speichern, stringifizieren Sie sie zunächst mit der JSON.stringify () -Methode.
Wenn Sie dann Daten abrufen möchten, müssen Sie die Zeichenfolge erneut in Objekt analysieren.
Ich hoffe es hilft.
quelle
Um ein Objekt zu speichern, können Sie Buchstaben erstellen, mit denen Sie ein Objekt von einer Zeichenfolge zu einem Objekt abrufen können (möglicherweise nicht sinnvoll). Zum Beispiel
Diese Technik verursacht einige Störungen, wenn Sie den Buchstaben verwenden, mit dem Sie das Objekt geteilt haben, und ist auch sehr experimentell.
quelle
Ich habe einen Weg gefunden, damit es mit Objekten funktioniert, die zyklische Referenzen haben.
Lassen Sie uns ein Objekt mit zyklischen Referenzen erstellen.
Wir können
JSON.stringify
hier wegen der Zirkelverweise nicht tun .LOCALSTORAGE.CYCLICJSON
hat.stringify
und.parse
wie normalJSON
, funktioniert aber mit Objekten mit Zirkelverweisen. ("Works" bedeutet parse (stringify (obj)) und obj sind tief gleich UND haben identische Mengen von 'inneren Gleichheiten')Aber wir können nur die Verknüpfungen verwenden:
Dann
recovered
wird "dasselbe" zu obj sein, im folgenden Sinne:Hier ist die Implementierung von
LOCALSTORAGE
quelle
localStorage.setItem ('Benutzer', JSON.stringify (Benutzer));
Um es dann aus dem Geschäft abzurufen und erneut in ein Objekt zu konvertieren:
var user = JSON.parse (localStorage.getItem ('user'));
Wenn wir alle Einträge des Geschäfts löschen müssen, können wir einfach Folgendes tun:
localStorage.clear ();
quelle