Shranjevanje predmetov v shrambo HTML5 localStorage

Rad bi shranil objekt JavaScript v HTML5 localStorage, vendar se moj objekt očitno pretvori v niz.

Primitivne vrste JavaScript in polja lahko shranim in prikličem z uporabo localStorage, vendar se zdi, da objekti ne delujejo. Ali bi morali?

Tukaj je moja koda:

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

Izpis v konzoli je

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

Zdi se mi, da metoda setItem pred shranjevanjem pretvori vnos v niz.

To vedenje vidim v brskalnikih Safari, Chrome in Firefox, zato domnevam, da gre za moje napačno razumevanje specifikacije HTML5 Web Storage in ne za napako ali omejitev, značilno za brskalnik.

Poskušal sem razumeti algoritem strukturiranega klona, opisan v http://www.w3.org/TR/html5/infrastructure.html. Ne razumem popolnoma, kaj je v njem zapisano, toda morda je moja težava povezana s tem, da lastnosti mojega predmeta niso naštevalne (????).

Ali obstaja enostaven način, kako to zaobiti?


Posodobitev: W3C si je sčasoma premislil o specifikaciji strukturiranega klona in se odločil spremeniti specifikacijo, da bo ustrezala izvedbam. Glej https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111. To vprašanje torej ni več 100-odstotno veljavno, vendar so odgovori nanj še vedno zanimivi.

Rešitev

Po pregledu dokumentacije Apple, Mozilla in spet Mozilla se zdi, da je funkcionalnost omejena samo na obdelavo parov ključ/vrednost v obliki niza.

To lahko obidete tako, da stringify svoj objekt pred shranjevanjem in ga pozneje razčlenite, ko ga prikličete:

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

Manjša izboljšava varianta:

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

Zaradi kratkoročnega vrednotenja getObject() takoj vrne null, če key ni v skladišču. Prav tako ne bo vrgel izjeme SyntaxError, če je value "" (prazen niz; JSON.parse() tega ne more obdelati).

Komentarji (10)

Morda se vam bo zdelo koristno razširiti objekt Storage s temi priročnimi metodami:

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

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

Na ta način boste dobili funkcionalnost, ki ste si jo resnično želeli, čeprav API podpira samo nize.

Komentarji (3)