Vraag Objecten opslaan in HTML5 localStorage


Ik wil een JavaScript-object opslaan in HTML5 localStorage, maar mijn object wordt blijkbaar geconverteerd naar een tekenreeks.

Ik kan primitieve JavaScript-typen en arrays gebruiken en opslaan localStorage, maar objecten lijken niet te werken. Moeten ze?

Hier is mijn 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);

De uitgang van de console is

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

Het lijkt mij het setItem methode is het converteren van de invoer naar een tekenreeks voordat deze wordt opgeslagen.

Ik zie dit gedrag in Safari, Chrome en Firefox, dus ik neem aan dat dit mijn misverstand is over de HTML5 Webopslag spec, geen browser-specifieke bug of beperking.

Ik heb geprobeerd de zin te begrijpen gestructureerde kloon algoritme beschreven in http://www.w3.org/TR/html5/infrastructure.html. Ik begrijp niet helemaal wat het zegt, maar misschien heeft mijn probleem te maken met het feit dat de eigenschappen van mijn object niet opsombaar zijn (???)

Is er een eenvoudige oplossing?


Update: de W3C veranderde uiteindelijk van mening over de specificatie van de gestructureerde kloon en besloot om de specificatie te wijzigen om overeen te komen met de implementaties. Zien https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111. Dus deze vraag is niet langer 100% geldig, maar de antwoorden kunnen nog steeds van belang zijn.


2051
2018-01-06 04:05


oorsprong


antwoorden:


Kijken naar de appel, Mozilla en Microsoft documentatie lijkt de functionaliteit beperkt te zijn om alleen string sleutel / waarde paren te behandelen.

Een workaround kan zijn om stringify je object voordat je het opslaat, en het later ontleedt wanneer je het ophaalt:

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

2650
2018-01-06 04:25



Een kleine verbetering op een 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);
}

Omdat kortsluiting evaluatie, getObject() zullen per direct terugkeer null als key bevindt zich niet in Opslag. Het zal ook niet gooien SyntaxError uitzondering als value is "" (de lege string; JSON.parse() kan dat niet).


562
2018-06-30 06:45



Wellicht vindt u het handig om het Storage-object uit te breiden met deze handige methoden:

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

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

Op deze manier krijgt u de functionaliteit die u echt wilde, hoewel onder de API alleen strings worden ondersteund.


195
2018-01-06 04:42



Het Storage-object uitbreiden is een geweldige oplossing. Voor mijn API heb ik een façade gemaakt voor localStorage en kijk ik vervolgens of het een object is of niet terwijl ik instel en krijg.

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

64
2018-01-21 18:29



Er is een geweldige bibliotheek die veel oplossingen bevat, zodat deze zelfs oudere browsers ondersteunt jStorage

U kunt een object instellen

$.jStorage.set(key, value)

En haal het gemakkelijk terug

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

52
2017-08-23 03:52



Stringify lost niet alle problemen op

Het lijkt erop dat de antwoorden hier niet alle typen bevatten die mogelijk zijn in JavaScript, dus hier zijn enkele korte voorbeelden van hoe u op de juiste manier met ze omgaat:

//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"

Ik raad het niet aan om functies op te slaan omdat eval() is slecht kan leiden tot problemen met betrekking tot beveiliging, optimalisatie en debugging.         In het algemeen, eval() mag nooit worden gebruikt in JavaScript-code.

Privé leden

Het probleem met het gebruik JSON.stringify()voor het opslaan van objecten is dat deze functie geen private leden kan serialiseren. Dit probleem kan worden opgelost door het overschrijven van .toString() methode (die impliciet wordt genoemd bij het opslaan van gegevens in webopslag):

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

Circulaire verwijzingen

Een ander probleem stringify kan niet omgaan met cirkelreferenties:

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

In dit voorbeeld JSON.stringify() zal gooien TypeError  "Cirkelstructuur converteren naar JSON".         Als het opslaan van circulaire verwijzingen moet worden ondersteund, de tweede parameter van JSON.stringify() kan worden gebruikt:

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

Het vinden van een efficiënte oplossing voor het opslaan van circulaire referenties is echter sterk afhankelijk van de taken die moeten worden opgelost en het herstellen van dergelijke gegevens is ook niet triviaal.

Er is al een vraag over SO om dit probleem aan te pakken: Stringify (converteren naar JSON) een JavaScript-object met kringverwijzing


50
2017-11-19 09:51



JSON-objecten gebruiken voor lokale opslag:

// SET

var m={name:'Hero',Title:'developer'};
localStorage.setItem('us', JSON.stringify(m));

//KRIJGEN

var gm =JSON.parse(localStorage.getItem('us'));
console.log(gm.name);

// Iteratie van alle sleutels en waarden voor lokale opslag

for (var i = 0, len = localStorage.length; i < len; ++i) {
  console.log(localStorage.getItem(localStorage.key(i)));
}

// VERWIJDEREN

localStorage.removeItem('us');
delete window.localStorage["us"];

29
2017-11-20 07:06



In theorie is het mogelijk om objecten met functies op te slaan:

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

Functie serialisatie / deserialisatie is echter onbetrouwbaar omdat het is implementatieafhankelijk.


27
2018-04-05 21:20



U kunt ook de standaardopslag negeren setItem(key,value) en getItem(key) methoden om objecten / arrays te behandelen zoals elk ander gegevenstype. Op die manier kun je gewoon bellen localStorage.setItem(key,value) en localStorage.getItem(key) zoals je normaal zou doen.

Ik heb dit niet uitgebreid getest, maar het bleek probleemloos te werken voor een klein project waar ik aan sleutelde.

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

Storage.prototype._getItem = Storage.prototype.getItem;
Storage.prototype.getItem = function(key)
{  
  try
  {
    return JSON.parse(this._getItem(key));
  }
  catch(e)
  {
    return this._getItem(key);
  }
}

22
2018-04-26 13:00



Ik ben bij deze post aangekomen na het raken van een ander bericht dat is afgesloten als een duplicaat hiervan - getiteld 'hoe een array in lokale opslag opslaan?'. Wat goed is, behalve dat geen enkele thread een volledig antwoord geeft over hoe je een array in localStorage kunt onderhouden - hoewel ik erin geslaagd ben om een ​​oplossing te maken op basis van informatie in beide threads.

Dus als iemand anders items in een array wil kunnen pushen / poppen / verplaatsen, en ze willen dat die array wordt opgeslagen in localStorage of zelfs sessionStorage, dan ga je hier:

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

voorbeeld gebruik - eenvoudige strings opslaan in localStorage array:

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

voorbeeld gebruik - het opslaan van objecten in 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);

gemeenschappelijke methoden om arrays te manipuleren:

.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

19
2018-05-07 11:35