Lagring av objekter i HTML5 localStorage

Jeg ønsker å lagre et JavaScript-objekt i HTML5 localStorage, men objektet mitt blir tilsynelatende konvertert til en streng.

Jeg kan lagre og hente primitive JavaScript-typer og matriser ved hjelp av localStorage, men objekter ser ikke ut til å fungere. Burde de gjøre det?

Her er koden min:

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

Konsollutgangen er

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

Det ser ut til at setItem-metoden konverterer inndata til en streng før den lagres.

Jeg ser denne oppførselen i Safari, Chrome og Firefox, så jeg antar at det er min misforståelse av HTML5 Web Storage spesifikasjonen, ikke en nettleser-spesifikk feil eller begrensning.

Jeg har prøvd å forstå structured clone-algoritmen som er beskrevet i http://www.w3.org/TR/html5/infrastructure.html. Jeg forstår ikke helt hva den sier, men kanskje problemet mitt har å gjøre med at objektets egenskaper ikke er oppregnede (???)

Finnes det en enkel løsning?


Oppdatering: W3C ombestemte seg til slutt om strukturert-klon-spesifikasjonen, og bestemte seg for å endre spesifikasjonen for å matche implementeringene. Se https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111. Så dette spørsmålet er ikke lenger 100 % gyldig, men svarene kan fortsatt være av interesse.

Løsning

Hvis man ser på dokumentasjonen til Apple, Mozilla og Mozilla igjen, ser funksjonaliteten ut til å være begrenset til å håndtere bare strengnøkkel/verdi-par.

En løsning kan være å stringify objektet ditt før du lagrer det, og senere analysere det når du henter det:

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

En mindre forbedring av en variant:

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

På grunn av kortslutningsevaluering, vil getObject() umiddelbart returnere null hvis key ikke er i Storage. Det vil heller ikke kaste et SyntaxError unntak hvis value er "" (den tomme strengen; JSON.parse() kan ikke håndtere det).

Kommentarer (10)

Det kan være nyttig å utvide lagringsobjektet med disse praktiske metodene:

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

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

På denne måten får du den funksjonaliteten du virkelig ønsket, selv om API-et under bare støtter strenger.

Kommentarer (3)