Speichern von Objekten in HTML5 localStorage


2511

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 setItemMethode 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.


17
Übrigens, Ihre Lesart des "strukturierten Klon-Algorithmus" ist korrekt. Es ist nur so, dass die Spezifikation nach dem Ende der Implementierungen von Nur-Zeichenfolgen-Werten auf diese Werte geändert wurde. Ich habe den Fehler bugzilla.mozilla.org/show_bug.cgi?id=538142 bei Mozilla eingereicht , um dieses Problem zu verfolgen.
Nickolay

2
Dies scheint ein Job für indexedDB zu sein ...
markasoftware

1
Wie wäre es mit dem Speichern eines Arrays von Objekten in localStorage? Ich habe das gleiche Problem, dass es in einen String konvertiert wird.
Jayant Pareek

1
Könnten Sie stattdessen einfach das Array serialisieren? Wie mit JSON stringify speichern und beim Laden erneut analysieren?
Brandito

1
Sie können localDataStorage verwenden , um Javascript-Datentypen (Array, Boolean, Date, Float, Integer, String und Object) transparent zu speichern
Mac

Antworten:


3170

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:

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

159
Beachten Sie, dass alle Metadaten entfernt werden. Sie erhalten nur ein Objekt mit den Schlüssel-Wert-Paaren, sodass jedes Objekt mit Verhalten neu erstellt werden muss.
Oligofren

5
@CMS kann setItem eine Ausnahme auslösen, wenn die Daten die Kapazität überschreiten?
Ashish Negi

3
... gilt nur für Objekte mit 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/2044940
CodeManX

3
Das Problem bei diesem Ansatz sind Leistungsprobleme, wenn Sie große Arrays oder Objekte verarbeiten müssen.
Mark

3
@oligofren wahr, aber wie Maja eval () => richtig vorgeschlagen hat, ist dies eine der guten Verwendungsmöglichkeiten. Sie können den Funktionscode einfach abrufen => als Zeichenfolge speichern und dann eval () zurückgeben :)
jave.web

621

Eine kleine Verbesserung gegenüber einer 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);
}

Wegen der Kurzauswertung , getObject()wird sofort zurückkehren , nullwenn keynicht Lager ist. Es wird auch keine SyntaxErrorAusnahme ausgelöst, wenn dies der Fall valueist ""(die leere Zeichenfolge; JSON.parse()kann damit nicht umgehen).


48
Ich möchte nur schnell die Verwendung hinzufügen, da es für mich nicht sofort klar war: var userObject = { userId: 24, name: 'Jack Bauer' }; Und um sie localStorage.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.
zuallauz

8
Es ist nur ein boolescher Ausdruck. Der zweite Teil wird nur ausgewertet, wenn der linke Teil wahr ist. In diesem Fall stammt das Ergebnis des gesamten Ausdrucks aus dem richtigen Teil. Es ist eine beliebte Technik, die auf der Art und Weise basiert, wie boolesche Ausdrücke ausgewertet werden.
Guria

4
Ich sehe den Punkt der lokalen Variablen und die Verknüpfungsbewertung hier nicht (abgesehen von geringfügigen Leistungsverbesserungen). Wenn keynicht im lokalen Speicher ist, window.localStorage.getItem(key)kehrt null- es ist nicht eine „Illegal Zugang“ Ausnahme auslösen - und JSON.parse(null)kehrt nullals auch - es ist nicht eine Ausnahme entweder werfen, weder in Chromium 21 noch pro IHM 5.1 Abschnitt 15.12.2 , weil String(null) === "null"die als JSON-Literal interpretiert werden .
PointedEars

6
Die Werte im lokalen Speicher sind immer primitive Zeichenfolgenwerte. Diese Verknüpfungsbewertung behandelt also, wenn jemand zuvor ""(die leere Zeichenfolge) gespeichert hat . Da es typkonvertiert in falseund JSON.parse(""), was eine SyntaxErrorAusnahme auslösen würde , wird es nicht aufgerufen.
PointedEars

2
Dies funktioniert in IE8 nicht, daher sollten Sie die Funktionen in der bestätigten Antwort besser verwenden, wenn Sie dies unterstützen müssen.
Ezeke

220

Möglicherweise ist es hilfreich, das Speicherobjekt mit den folgenden 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 unter der API nur Zeichenfolgen unterstützt werden.


13
Das Einschließen des CMS-Ansatzes in eine Funktion ist eine gute Idee. Es sind lediglich Funktionstests erforderlich: Einer für JSON.stringify, einer für JSON.parse und einer zum Testen, ob localStorage tatsächlich ein Objekt festlegen und abrufen kann. Das Ändern von Hostobjekten ist keine gute Idee. Ich würde dies lieber als separate Methode sehen und nicht als localStorage.setObject.
Garrett

4
Dies getObject()löst eine SyntaxErrorAusnahme aus, wenn der gespeicherte Wert lautet "", da JSON.parse()dies nicht möglich ist. Siehe meine Bearbeitung von Gurias Antwort für Details.
PointedEars

9
Nur meine zwei Cent, aber ich bin mir ziemlich sicher, dass es keine gute Idee ist, die vom Anbieter bereitgestellten Objekte so zu erweitern.
Sethen


73

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.

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

1
Das war fast genau das, was ich brauchte. Musste nur if (value == null) {return false} vor dem Kommentar hinzufügen, sonst führte dies zu einem Fehler beim Überprüfen des Vorhandenseins eines Schlüssels in localStorage.
Francesco Frapporti

2
Das ist eigentlich ziemlich cool. Stimmen Sie mit @FrancescoFrapporti überein, dass Sie dort ein Wenn für Nullwerte benötigen. Ich habe auch ein '|| hinzugefügt value [0] == "[" 'testet für den Fall, dass sich dort ein Array befindet.
rob_james

Guter Punkt, ich werde das bearbeiten. Sie brauchen zwar nicht den Nullteil, aber wenn Sie das tun, empfehle ich drei ===. Wenn Sie JSHint oder JSLint verwenden, werden Sie vor der Verwendung von == gewarnt.
Alex Grande

3
Und für Nicht-Ninjas (wie mich) könnte jemand bitte ein Verwendungsbeispiel für diese Antwort liefern? Ist es : data.set('username': 'ifedi', 'fullname': { firstname: 'Ifedi', lastname: 'Okonkwo'});?
Ifedi Okonkwo

Ja in der Tat! Als ich meinen Wunsch, mit dem Löffel gefüttert zu werden, überwunden hatte, nahm ich den Code zum Testen und bekam ihn. Ich finde diese Antwort großartig, weil 1) im Gegensatz zur akzeptierten Antwort einige Zeit benötigt wird, um bestimmte Zeichenfolgendaten zu überprüfen, und 2) im Gegensatz zur nächsten ein natives Objekt nicht erweitert wird.
Ifedi Okonkwo

64

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:

//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, weileval() dies zu Problemen in Bezug auf Sicherheit, Optimierung und Debugging führen kann. Im Allgemeinen eval()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):

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

Rundschreiben

Ein weiteres Problem, mit dem stringifyman sich nicht befassen kann, sind Zirkelverweise:

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

In diesem Beispiel JSON.stringify()wird eine TypeError "Konvertieren einer kreisförmigen Struktur in JSON" ausgelöst . Wenn das Speichern von Zirkelverweisen unterstützt werden soll, kann der zweite Parameter von JSON.stringify()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 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


2
Daher und natürlich sollte das Speichern von Daten im Speicher auf der alleinigen Voraussetzung von Kopien einfacher Daten beruhen . Keine lebenden Objekte.
Roko C. Buljan

51

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

$.jStorage.set(key, value)

Und einfach abrufen

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

2
@ SuperUberDuper jStorage erfordert Prototype, MooTools oder jQuery
JProgrammer

28

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, da sie implementierungsabhängig ist .


1
Die Serialisierung / Deserialisierung von Funktionen ist unzuverlässig, da sie implementierungsabhängig ist . Außerdem möchten Sie durch c.f[k] = escape(a[k]); den Unicode-Safe c.f[k] = encodeURIComponent(a[k]);und eval('b.' + k + ' = ' + unescape(data.f[k]));durch ersetzen b[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 / (so eval()) würde SyntaxErrorsonst eine Ausnahme auslösen).
PointedEars

Und typeofist ein Operator , schreiben Sie es nicht so, als ob es eine Funktion wäre. Ersetzen typeof(a[k])durch typeof a[k].
PointedEars

Zusätzlich zur Anwendung meiner Vorschläge und zur Betonung der Unzuverlässigkeit des Ansatzes habe ich die folgenden Fehler behoben: 1. Nicht alle Variablen wurden deklariert. 2. for- inwurde nicht nach eigenen Eigenschaften gefiltert. 3. Der Codestil, einschließlich der Referenzierung, war inkonsistent.
PointedEars

@PointedEars Welchen praktischen Unterschied macht das? Die Spezifikation besagt, dass the use and placement of white space, line terminators, and semicolons within the representation String is implementation-dependent. ich keine funktionalen Unterschiede sehe.
Michael

@ Michael Der Teil, den Sie zitiert haben, beginnt mit Note *in particular* that …. Die Rückgabewertspezifikation beginnt jedoch mit An implementation-dependent representation of the function is returned. This representation has the syntax of a FunctionDeclaration.Der Rückgabewert kann sein function foo () {}- unter der Annahme einer konformen Implementierung.
PointedEars

22

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:

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

Beispiel für die Verwendung - Speichern einfacher Zeichenfolgen im localStorage-Array:

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

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

gängige 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

Dies ist eine sehr praktische Reihe von Methoden zum Bearbeiten von Arrays, die in localStorage oder sessionStorage gespeichert sind, und verdient viel mehr Anerkennung als angezogen. @Andy Lorenz Danke, dass du dir die Zeit zum Teilen genommen hast!
Velojet



6

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:

localDataStorage.set( 'key1', 'Belgian' )
localDataStorage.set( 'key2', 1200.0047 )
localDataStorage.set( 'key3', true )
localDataStorage.set( 'key4', { 'RSK' : [1,'3',5,'7',9] } )
localDataStorage.set( 'key5', null )

localDataStorage.get( 'key1' )   -->   'Belgian'
localDataStorage.get( 'key2' )   -->   1200.0047
localDataStorage.get( 'key3' )   -->   true
localDataStorage.get( 'key4' )   -->   Object {RSK: Array(5)}
localDataStorage.get( 'key5' )   -->   null

Wie Sie sehen können, werden die primitiven Werte respektiert.


1
Dies ist eine brillante Ressource und genau das, was ich brauche. Ich mache Ionic-Apps mit AngularJS, bei denen ich bestimmte Javascript-Objekte in localStorage speichern muss. Bis zu diesem Punkt habe ich nur JSON.parse und JSON.stringify ausgeführt, und sie funktionieren, aber es ist etwas umständlicher als möglich um nur ein Dienstprogramm wie dieses zu verwenden. Ich werde es versuchen.
Nmuta

4

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.

Persisto-Funktionen

(Haftungsausschluss: Ich bin der Autor.)


Ich arbeite immer noch an meiner Readme- Datei , aber für meine Version ist jQuery nicht erforderlich , wie es persisto scheint, aber es bietet eine Alternative für den Umgang mit jQuery-Elementobjekten. Ich werde in naher Zukunft weitere hinzufügen, da ich mehr damit arbeite, um verschiedene jQuery-Objekte besser zu handhaben und Dinge wie persistente Daten zu verwalten. Außerdem +1 für den Versuch, eine einfachere Lösung bereitzustellen! Außerdem werden alle traditionellen Methoden von verwendet localStroage; exp: var lsh = new localStorageHelper(); lsh.setItem('bob', 'bill'); Enthält auch Ereignisse.
SpYk3HH

4

Sie können ejson verwenden , um die Objekte als Zeichenfolgen zu speichern.

EJSON ist eine Erweiterung von JSON, um weitere Typen zu unterstützen. Es unterstützt alle JSON-sicheren Typen sowie:

Alle EJSON-Serialisierungen sind auch gültige JSON. Beispielsweise würde ein Objekt mit einem Datum und einem Binärpuffer in EJSON wie folgt serialisiert:

{
  "d": {"$date": 1358205756553},
  "b": {"$binary": "c3VyZS4="}
}

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


2

Ich habe einen weiteren minimalistischen Wrapper mit nur 20 Codezeilen erstellt, damit er so verwendet werden kann, wie er sollte:

localStorage.set('myKey',{a:[1,2,5], b: 'ok'});
localStorage.has('myKey');   // --> true
localStorage.get('myKey');   // --> {a:[1,2,5], b: 'ok'}
localStorage.keys();         // --> ['myKey']
localStorage.remove('myKey');

https://github.com/zevero/simpleWebstorage


2

Für Typescript-Benutzer, die typisierte Eigenschaften festlegen und abrufen möchten:

/**
 * Silly wrapper to be able to type the storage keys
 */
export class TypedStorage<T> {

    public removeItem(key: keyof T): void {
        localStorage.removeItem(key);
    }

    public getItem<K extends keyof T>(key: K): T[K] | null {
        const data: string | null =  localStorage.getItem(key);
        return JSON.parse(data);
    }

    public setItem<K extends keyof T>(key: K, value: T[K]): void {
        const data: string = JSON.stringify(value);
        localStorage.setItem(key, data);
    }
}

Anwendungsbeispiel :

// write an interface for the storage
interface MyStore {
   age: number,
   name: string,
   address: {city:string}
}

const storage: TypedStorage<MyStore> = new TypedStorage<MyStore>();

storage.setItem("wrong key", ""); // error unknown key
storage.setItem("age", "hello"); // error, age should be number
storage.setItem("address", {city:"Here"}); // ok

const address: {city:string} = storage.getItem("address");

2

https://github.com/adrianmay/rhaboo ist eine localStorage-Zuckerschicht, mit der Sie Folgendes schreiben können:

var store = Rhaboo.persistent('Some name');
store.write('count', store.count ? store.count+1 : 1);
store.write('somethingfancy', {
  one: ['man', 'went'],
  2: 'mow',
  went: [  2, { mow: ['a', 'meadow' ] }, {}  ]
});
store.somethingfancy.went[1].mow.write(1, 'lawn');

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.


1

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:

var PT=Storage.prototype

if (typeof PT._setItem >='u') PT._setItem = PT.setItem;
PT.setItem = function(key, value)
{
  if (typeof value >='u')//..ndefined
    this.removeItem(key)
  else
    this._setItem(key, JSON.stringify(value));
}

if (typeof PT._getItem >='u') PT._getItem = PT.getItem;
PT.getItem = function(key)
{  
  var ItemData = this._getItem(key)
  try
  {
    return JSON.parse(ItemData);
  }
  catch(e)
  {
    return ItemData;
  }
}

// Aliases for localStorage.set/getItem 
get =   localStorage.getItem.bind(localStorage)
set =   localStorage.setItem.bind(localStorage)

// Create ConfigWrapperObject
var config = {}

// Helper to create getter & setter
function configCreate(PropToAdd){
    Object.defineProperty( config, PropToAdd, {
      get: function ()      { return (  get(PropToAdd)      ) },
      set: function (val)   {           set(PropToAdd,  val ) }
    })
}
//------------------------------

// Usage Part
// Create properties
configCreate('preview')
configCreate('notification')
//...

// Config Data transfer
//set
config.preview = true

//get
config.preview

// delete
config.preview = undefined

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 einfaches get = localStorage.getItem;nicht funktioniert


1

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 localStorageEigenschaft magisch ist:

var prop = ObjectStorage(localStorage, 'prop');

Wenn Sie mehrere benötigen:

var storage = ObjectStorage(localStorage, ['prop', 'more', 'props']);

Alles , was Sie tun , um prop, oder die Objekte innerhalb storage automatisch in gespeichert werden localStorage. Du spielst immer mit einem echten Objekt, also kannst du solche Dinge tun:

storage.data.list.push('more data');
storage.another.list.splice(1, 2, {another: 'object'});

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.


1

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.

var myObj = [{name:"test", time:"Date 2017-02-03T08:38:04.449Z"}];
localStorage.setItem('item', JSON.stringify(myObj));

Wenn Sie dann Daten abrufen möchten, müssen Sie die Zeichenfolge erneut in Objekt analysieren.

var getObj = JSON.parse(localStorage.getItem('item'));

Ich hoffe es hilft.


0

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

var obj = {a: "lol", b: "A", c: "hello world"};
function saveObj (key){
    var j = "";
    for(var i in obj){
        j += (i+"|"+obj[i]+"~");
    }
    localStorage.setItem(key, j);
} // Saving Method
function getObj (key){
    var j = {};
    var k = localStorage.getItem(key).split("~");
    for(var l in k){
        var m = k[l].split("|");
        j[m[0]] = m[1];
    }
    return j;
}
saveObj("obj"); // undefined
getObj("obj"); // {a: "lol", b: "A", c: "hello world"}

Diese Technik verursacht einige Störungen, wenn Sie den Buchstaben verwenden, mit dem Sie das Objekt geteilt haben, und ist auch sehr experimentell.


0

Ich habe einen Weg gefunden, damit es mit Objekten funktioniert, die zyklische Referenzen haben.

Lassen Sie uns ein Objekt mit zyklischen Referenzen erstellen.

obj = {
    L: {
        L: { v: 'lorem' },
        R: { v: 'ipsum' }
    },
    R: {
        L: { v: 'dolor' },
        R: {
            L: { v: 'sit' },
            R: { v: 'amet' }
        }
    }
}
obj.R.L.uncle = obj.L;
obj.R.R.uncle = obj.L;
obj.R.R.L.uncle = obj.R.L;
obj.R.R.R.uncle = obj.R.L;
obj.L.L.uncle = obj.R;
obj.L.R.uncle = obj.R;

Wir können JSON.stringifyhier wegen der Zirkelverweise nicht tun .

CircularUncle

LOCALSTORAGE.CYCLICJSONhat .stringifyund .parsewie normal JSON, 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:

LOCALSTORAGE.setObject('latinUncles', obj)
recovered = LOCALSTORAGE.getObject('latinUncles')

Dann recoveredwird "dasselbe" zu obj sein, im folgenden Sinne:

[
obj.L.L.v === recovered.L.L.v,
obj.L.R.v === recovered.L.R.v,
obj.R.L.v === recovered.R.L.v,
obj.R.R.L.v === recovered.R.R.L.v,
obj.R.R.R.v === recovered.R.R.R.v,
obj.R.L.uncle === obj.L,
obj.R.R.uncle === obj.L,
obj.R.R.L.uncle === obj.R.L,
obj.R.R.R.uncle === obj.R.L,
obj.L.L.uncle === obj.R,
obj.L.R.uncle === obj.R,
recovered.R.L.uncle === recovered.L,
recovered.R.R.uncle === recovered.L,
recovered.R.R.L.uncle === recovered.R.L,
recovered.R.R.R.uncle === recovered.R.L,
recovered.L.L.uncle === recovered.R,
recovered.L.R.uncle === recovered.R
]

Hier ist die Implementierung von LOCALSTORAGE

LOCALSTORAGE = (function(){
  "use strict";
  var ignore = [Boolean, Date, Number, RegExp, String];
  function primitive(item){
    if (typeof item === 'object'){
      if (item === null) { return true; }
      for (var i=0; i<ignore.length; i++){
        if (item instanceof ignore[i]) { return true; }
      }
      return false;
    } else {
      return true;
    }
  }
  function infant(value){
    return Array.isArray(value) ? [] : {};
  }
  function decycleIntoForest(object, replacer) {
    if (typeof replacer !== 'function'){
      replacer = function(x){ return x; }
    }
    object = replacer(object);
    if (primitive(object)) return object;
    var objects = [object];
    var forest  = [infant(object)];
    var bucket  = new WeakMap(); // bucket = inverse of objects 
    bucket.set(object, 0);    
    function addToBucket(obj){
      var result = objects.length;
      objects.push(obj);
      bucket.set(obj, result);
      return result;
    }
    function isInBucket(obj){ return bucket.has(obj); }
    function processNode(source, target){
      Object.keys(source).forEach(function(key){
        var value = replacer(source[key]);
        if (primitive(value)){
          target[key] = {value: value};
        } else {
          var ptr;
          if (isInBucket(value)){
            ptr = bucket.get(value);
          } else {
            ptr = addToBucket(value);
            var newTree = infant(value);
            forest.push(newTree);
            processNode(value, newTree);
          }
          target[key] = {pointer: ptr};
        }
      });
    }
    processNode(object, forest[0]);
    return forest;
  };
  function deForestIntoCycle(forest) {
    var objects = [];
    var objectRequested = [];
    var todo = [];
    function processTree(idx) {
      if (idx in objects) return objects[idx];
      if (objectRequested[idx]) return null;
      objectRequested[idx] = true;
      var tree = forest[idx];
      var node = Array.isArray(tree) ? [] : {};
      for (var key in tree) {
        var o = tree[key];
        if ('pointer' in o) {
          var ptr = o.pointer;
          var value = processTree(ptr);
          if (value === null) {
            todo.push({
              node: node,
              key: key,
              idx: ptr
            });
          } else {
            node[key] = value;
          }
        } else {
          if ('value' in o) {
            node[key] = o.value;
          } else {
            throw new Error('unexpected')
          }
        }
      }
      objects[idx] = node;
      return node;
    }
    var result = processTree(0);
    for (var i = 0; i < todo.length; i++) {
      var item = todo[i];
      item.node[item.key] = objects[item.idx];
    }
    return result;
  };
  var console = {
    log: function(x){
      var the = document.getElementById('the');
      the.textContent = the.textContent + '\n' + x;
	},
	delimiter: function(){
      var the = document.getElementById('the');
      the.textContent = the.textContent +
		'\n*******************************************';
	}
  }
  function logCyclicObjectToConsole(root) {
    var cycleFree = decycleIntoForest(root);
    var shown = cycleFree.map(function(tree, idx) {
      return false;
    });
    var indentIncrement = 4;
    function showItem(nodeSlot, indent, label) {
      var leadingSpaces = ' '.repeat(indent);
      var leadingSpacesPlus = ' '.repeat(indent + indentIncrement);
      if (shown[nodeSlot]) {
        console.log(leadingSpaces + label + ' ... see above (object #' + nodeSlot + ')');
      } else {
        console.log(leadingSpaces + label + ' object#' + nodeSlot);
        var tree = cycleFree[nodeSlot];
        shown[nodeSlot] = true;
        Object.keys(tree).forEach(function(key) {
          var entry = tree[key];
          if ('value' in entry) {
            console.log(leadingSpacesPlus + key + ": " + entry.value);
          } else {
            if ('pointer' in entry) {
              showItem(entry.pointer, indent + indentIncrement, key);
            }
          }
        });
      }
    }
	console.delimiter();
    showItem(0, 0, 'root');
  };
  function stringify(obj){
    return JSON.stringify(decycleIntoForest(obj));
  }
  function parse(str){
    return deForestIntoCycle(JSON.parse(str));
  }
  var CYCLICJSON = {
    decycleIntoForest: decycleIntoForest,
    deForestIntoCycle : deForestIntoCycle,
    logCyclicObjectToConsole: logCyclicObjectToConsole,
    stringify : stringify,
    parse : parse
  }
  function setObject(name, object){
    var str = stringify(object);
    localStorage.setItem(name, str);
  }
  function getObject(name){
    var str = localStorage.getItem(name);
    if (str===null) return null;
    return parse(str);
  }
  return {
    CYCLICJSON : CYCLICJSON,
    setObject  : setObject,
    getObject  : getObject
  }
})();
obj = {
	L: {
		L: { v: 'lorem' },
		R: { v: 'ipsum' }
	},
	R: {
		L: { v: 'dolor' },
		R: {
			L: { v: 'sit' },
			R: { v: 'amet' }
		}
	}
}
obj.R.L.uncle = obj.L;
obj.R.R.uncle = obj.L;
obj.R.R.L.uncle = obj.R.L;
obj.R.R.R.uncle = obj.R.L;
obj.L.L.uncle = obj.R;
obj.L.R.uncle = obj.R;

// LOCALSTORAGE.setObject('latinUncles', obj)
// recovered = LOCALSTORAGE.getObject('latinUncles')
// localStorage not available inside fiddle ):
LOCALSTORAGE.CYCLICJSON.logCyclicObjectToConsole(obj)
putIntoLS = LOCALSTORAGE.CYCLICJSON.stringify(obj);
recovered = LOCALSTORAGE.CYCLICJSON.parse(putIntoLS);
LOCALSTORAGE.CYCLICJSON.logCyclicObjectToConsole(recovered);

var the = document.getElementById('the');
the.textContent = the.textContent + '\n\n' +
JSON.stringify(
[
obj.L.L.v === recovered.L.L.v,
obj.L.R.v === recovered.L.R.v,
obj.R.L.v === recovered.R.L.v,
obj.R.R.L.v === recovered.R.R.L.v,
obj.R.R.R.v === recovered.R.R.R.v,
obj.R.L.uncle === obj.L,
obj.R.R.uncle === obj.L,
obj.R.R.L.uncle === obj.R.L,
obj.R.R.R.uncle === obj.R.L,
obj.L.L.uncle === obj.R,
obj.L.R.uncle === obj.R,
recovered.R.L.uncle === recovered.L,
recovered.R.R.uncle === recovered.L,
recovered.R.R.L.uncle === recovered.R.L,
recovered.R.R.R.uncle === recovered.R.L,
recovered.L.L.uncle === recovered.R,
recovered.L.R.uncle === recovered.R
]
)
<pre id='the'></pre>


-2

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


3
Dies ist eine 10 Jahre alte Frage. Denken Sie, dass Ihre Antwort etwas hinzufügt, das noch nicht in den anderen Antworten enthalten ist?
Kristopher Johnson
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.