Jag vill lagra ett JavaScript-objekt i HTML5 localStorage
, men mitt objekt konverteras tydligen till en sträng.
Jag kan lagra och hämta primitiva JavaScript-typer och matriser med hjälp av localStorage
, men objekt verkar inte fungera. Borde de det?
Här är min kod:
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);
Konsolutgången är
typeof testObject: object
testObject properties:
one: 1
two: 2
three: 3
typeof retrievedObject: string
Value of retrievedObject: [object Object]
Det ser ut som om metoden setItem
konverterar inmatningen till en sträng innan den lagras.
Jag ser det här beteendet i Safari, Chrome och Firefox, så jag antar att det är min missuppfattning av HTML5 Web Storage spec, inte ett webbläsarspecifikt fel eller en begränsning.
Jag har försökt förstå algoritmen structured clone som beskrivs i http://www.w3.org/TR/html5/infrastructure.html. Jag förstår inte helt vad den säger, men kanske har mitt problem att göra med att mina objektegenskaper inte är uppräknningsbara (?????).
Finns det en enkel lösning?
Uppdatering: W3C ändrade sig så småningom om specifikationen för strukturerade kloner och beslutade att ändra specifikationen så att den stämmer överens med implementeringarna. Se https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111. Frågan är alltså inte längre 100 % giltig, men svaren kan fortfarande vara av intresse.
Om man tittar på dokumentationen för Apple, Mozilla och Mozilla again verkar funktionaliteten vara begränsad till att endast hantera strängnyckel/värdepar.
En lösning kan vara att strängifiera ditt objekt innan du lagrar det och senare analysera det när du hämtar 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));
En liten förbättring 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å grund av [short-circuit evaluation] (http://en.wikipedia.org/wiki/Short-circuit_evaluation) kommer getObject()
att omedelbart returnera null
om key
inte finns i Storage. Den kommer inte heller att kasta ett SyntaxError
undantag om value
är ""
(den tomma strängen; JSON.parse()
kan inte hantera det).
Det kan vara användbart att utöka Storage-objektet med dessa praktiska metoder:
Storage.prototype.setObject = function(key, value) {
this.setItem(key, JSON.stringify(value));
}
Storage.prototype.getObject = function(key) {
return JSON.parse(this.getItem(key));
}
På så sätt får du den funktionalitet som du egentligen ville ha trots att API:et endast stöder strängar.