Archiviazione di oggetti in HTML5 localStorage


2511

Vorrei archiviare un oggetto JavaScript in HTML5 localStorage, ma il mio oggetto apparentemente viene convertito in una stringa.

Posso archiviare e recuperare tipi e array JavaScript primitivi usando localStorage, ma gli oggetti non sembrano funzionare. Dovrebbero?

Ecco il mio codice:

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

L'output della console è

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

Mi sembra che il setItemmetodo stia convertendo l'input in una stringa prima di memorizzarlo.

Vedo questo comportamento in Safari, Chrome e Firefox, quindi presumo sia il mio fraintendimento delle specifiche di archiviazione Web HTML5 , non un bug specifico o una limitazione.

Ho cercato di dare un senso all'algoritmo del clone strutturato descritto in http://www.w3.org/TR/html5/infrastructure.html . Non capisco bene cosa stia dicendo, ma forse il mio problema ha a che fare con le proprietà del mio oggetto che non sono enumerabili (???)

C'è una soluzione semplice?


Aggiornamento: il W3C alla fine ha cambiato idea sulle specifiche del clone strutturato e ha deciso di cambiare le specifiche per adattarle alle implementazioni. Vedi https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111 . Quindi questa domanda non è più valida al 100%, ma le risposte possono ancora essere interessanti.


17
A proposito, la tua lettura dell '"algoritmo del clone strutturato" è corretta, è solo che la specifica è stata cambiata da valori solo stringa a questo dopo che le implementazioni sono state lanciate. Ho archiviato bug bugzilla.mozilla.org/show_bug.cgi?id=538142 con mozilla per tenere traccia di questo problema.
Nickolay,

2
Sembra un lavoro per IndexedDB ...
markasoftware il

1
Che ne dite di archiviare un array di oggetti in localStorage? Sto affrontando lo stesso problema che viene convertito in stringa.
Jayant Pareek,

1
potresti invece serializzare l'array? come negozio con JSON stringify quindi analizzare nuovamente al caricamento?
Brandito,

1
Puoi usare localDataStorage per archiviare in modo trasparente tipi di dati javascript (Array, Boolean, Date, Float, Integer, String e Object)
Mac

Risposte:


3173

Guardando di nuovo la documentazione di Apple , Mozilla e Mozilla , la funzionalità sembra essere limitata per gestire solo coppie chiave / valore stringa.

Una soluzione alternativa può essere quella di stringere il tuo oggetto prima di memorizzarlo e successivamente analizzarlo quando lo recuperi:

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

160
osserva che eventuali metadati verranno rimossi. ottieni solo un oggetto con le coppie chiave-valore, quindi qualsiasi oggetto con comportamento deve essere ricostruito.
Oligofren,

5
@CMS può impostareItem gettare qualche eccezione se i dati sono oltre la capacità?
Ashish Negi,

3
... si applica solo agli oggetti con riferimenti circolari, JSON.stringify()espande l'oggetto a cui fa riferimento al suo "contenuto" completo (implicitamente stringito) nell'oggetto che stringiamo. Vedi: stackoverflow.com/a/12659424/2044940
CodeManX

3
Il problema con questo approccio sono problemi di prestazioni, se è necessario gestire matrici o oggetti di grandi dimensioni.
Segna il

3
@oligofren true, ma come ha suggerito correttamente maja eval () =>, questo è uno dei buoni usi di, puoi facilmente recuperare il codice funzione => archiviarlo come stringa e quindi eval () indietro :)
jave.web

621

Un piccolo miglioramento su una 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);
}

A causa della valutazione di corto circuito , getObject()sarà immediatamente tornare nullse keynon è in deposito. Inoltre non genererà SyntaxErrorun'eccezione se valueè ""(la stringa vuota; JSON.parse()non può gestirla).


48
Voglio solo aggiungere rapidamente l'uso in quanto non è stato immediatamente chiaro per me: var userObject = { userId: 24, name: 'Jack Bauer' }; E per impostarlo localStorage.setObject('user', userObject); Quindi ripristinarlo dallo spazio di archiviazione userObject = localStorage.getObject('user'); È anche possibile archiviare una serie di oggetti se lo si desidera.
zuallauz,

8
È solo un'espressione booleana. La seconda parte viene valutata solo se quella sinistra è vera. In tal caso il risultato dell'intera espressione sarà dalla parte giusta. È una tecnica popolare basata sul modo in cui vengono valutate le espressioni booleane.
Guria,

4
Non vedo il punto della variabile locale e la valutazione del collegamento qui (piccoli miglioramenti delle prestazioni a parte). Se keynon si trova nella memoria locale, window.localStorage.getItem(key)restituisce null- non genera un'eccezione "Accesso illegale" - e JSON.parse(null)restituisce nullanche - non genera nemmeno un'eccezione, né in Chromium 21 né in ES 5.1 sezione 15.12.2 , perché String(null) === "null"ciò può essere interpretato come un letterale JSON .
Pointed Ears

6
I valori nella memoria locale sono sempre valori di stringa primitivi. Quindi ciò che questa valutazione di scorciatoia gestisce è quando qualcuno ha archiviato ""(la stringa vuota) prima. Perché si converte in tipo falsee JSON.parse(""), che genererebbe SyntaxErrorun'eccezione, non viene chiamato.
Pointed Ears

2
Questo non funzionerà in IE8, quindi è meglio usare le funzioni nella risposta confermata se è necessario supportarlo.
Ezeke,

220

Potresti trovare utile estendere l'oggetto Storage con questi pratici metodi:

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

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

In questo modo ottieni le funzionalità che volevi davvero anche se sotto l'API supporta solo le stringhe.


13
Avvolgere l'approccio di CMS in una funzione è una buona idea, ha solo bisogno di un test di funzionalità: uno per JSON.stringify, uno per JSON.parse e uno per verificare se localStorage può effettivamente impostare e recuperare un oggetto. La modifica di oggetti host non è una buona idea; Preferirei vedere questo come un metodo separato e non come localStorage.setObject.
Garrett,

4
Questo getObject() genererà SyntaxErrorun'eccezione se il valore memorizzato è "", perché JSON.parse()non è in grado di gestirlo. Vedi la mia modifica alla risposta di Guria per i dettagli.
Pointed Ears

9
Solo i miei due centesimi, ma sono abbastanza sicuro che non sia una buona idea estendere gli oggetti forniti dal venditore in questo modo.
Sethen,


73

L'estensione dell'oggetto Storage è una soluzione eccezionale. Per la mia API, ho creato una facciata per localStorage e quindi controlla se si tratta di un oggetto o meno durante l'impostazione e il recupero.

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
Questo era quasi esattamente quello di cui avevo bisogno. Ho dovuto solo aggiungere if (value == null) {return false} prima del commento, altrimenti si è verificato un errore durante il controllo dell'esistenza di una chiave su localStorage.
Francesco Frapporti,

2
Questo è piuttosto bello in realtà. D'accordo con @FrancescoFrapporti hai bisogno di un if per valori null. Ho anche aggiunto un '|| valore [0] == "[" 'test nel caso in cui vi sia un array.
rob_james,

Buon punto, lo modificherò. Anche se non hai bisogno della parte nulla, ma se lo fai ti consiglio tre ===. Se usi JSHint o JSLint verrai avvisato di non usare ==.
Alex Grande,

3
E per i non ninja (come me) qualcuno potrebbe fornire un esempio di utilizzo per questa risposta? È data.set('username': 'ifedi', 'fullname': { firstname: 'Ifedi', lastname: 'Okonkwo'});:?
Ifedi Okonkwo,

Si Certamente! Quando ho superato il mio desiderio di essere nutrito a cucchiaio, ho preso il codice per testarlo e l'ho preso. Penso che questa risposta sia ottima perché 1) A differenza della risposta accettata, ci vuole tempo per fare alcuni controlli sui dati della stringa, e 2) A differenza della successiva, non va ad estendere un oggetto nativo.
Ifedi Okonkwo,

64

Stringify non risolve tutti i problemi

Sembra che le risposte qui non coprano tutti i tipi possibili in JavaScript, quindi ecco alcuni brevi esempi su come gestirli correttamente:

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

Non consiglio di archiviare le funzioni perché il eval()male può portare a problemi di sicurezza, ottimizzazione e debug. In generale, eval()non dovrebbe mai essere usato nel codice JavaScript.

Membri privati

Il problema con l'utilizzo JSON.stringify()per la memorizzazione di oggetti è che questa funzione non può serializzare i membri privati. Questo problema può essere risolto sovrascrivendo il .toString()metodo (che viene chiamato implicitamente quando si archiviano i dati nella memoria Web):

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

Riferimenti circolari

Un altro problema stringifynon risolvibile sono i riferimenti circolari:

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

In questo esempio, JSON.stringify()verrà generata una TypeError "Conversione della struttura circolare in JSON" . Se è necessario supportare la memorizzazione di riferimenti circolari, è JSON.stringify()possibile utilizzare il secondo parametro di :

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

Tuttavia, trovare una soluzione efficiente per la memorizzazione di riferimenti circolari dipende fortemente dalle attività che devono essere risolte e il ripristino di tali dati non è nemmeno banale.

Esistono già alcune domande su SO che affronta questo problema: Stringify (converti in JSON) un oggetto JavaScript con riferimento circolare


2
Pertanto, e inutile dirlo, la memorizzazione dei dati nell'archiviazione dovrebbe essere basata sull'unica premessa delle copie di dati semplici. Oggetti non vivi.
Roko C. Buljan,

51

C'è una grande libreria che racchiude molte soluzioni in modo da supportare anche i browser più vecchi chiamati jStorage

È possibile impostare un oggetto

$.jStorage.set(key, value)

E recuperalo facilmente

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

2
@SuperUberDuper jStorage richiede Prototype, MooTools o jQuery
JProgrammer

28

In teoria, è possibile memorizzare oggetti con funzioni:

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

Tuttavia, la serializzazione / deserializzazione delle funzioni non è affidabile perché dipende dall'implementazione .


1
La serializzazione / deserializzazione delle funzioni non è affidabile perché dipende dall'implementazione . Inoltre, si desidera sostituire c.f[k] = escape(a[k]); con Unicode-safe c.f[k] = encodeURIComponent(a[k]);e eval('b.' + k + ' = ' + unescape(data.f[k]));con b[k] = eval("(" + decodeURIComponent(data.f[k]) + ")");. Le parentesi sono necessarie perché la tua funzione, se serializzata correttamente, è probabile che sia anonima, che non è così com'è / L'istruzione / (quindi eval()) genererebbe SyntaxErrorun'eccezione altrimenti).
Pointed Ears

Ed typeofè un operatore , non scriverlo come se fosse una funzione. Sostituisci typeof(a[k])con typeof a[k].
Pointed Ears

Oltre ad applicare i miei suggerimenti e sottolineare l'ineffidabilità dell'approccio, ho corretto i seguenti bug: 1. Non tutte le variabili sono state dichiarate. 2. for- innon è stato filtrato per le proprie proprietà. 3. Lo stile del codice, incluso il riferimento, era incoerente.
Pointed Ears

@PointedEars che differenza pratica fa questo? la specifica dice the use and placement of white space, line terminators, and semicolons within the representation String is implementation-dependent. che non vedo differenze funzionali.
Michael,

@Michael La parte che hai citato inizia con Note *in particular* that …. Ma la specifica del valore restituito inizia con An implementation-dependent representation of the function is returned. This representation has the syntax of a FunctionDeclaration.Il valore restituito può essere function foo () {}- presupponendo un'implementazione conforme .
Orecchie appuntite

22

Sono arrivato a questo post dopo aver colpito un altro post che è stato chiuso come un duplicato di questo - intitolato "come archiviare un array nello store locale?". Il che va bene tranne che nessuno dei thread fornisce effettivamente una risposta completa su come è possibile mantenere un array in localStorage - tuttavia sono riuscito a creare una soluzione basata sulle informazioni contenute in entrambi i thread.

Quindi, se qualcun altro vuole essere in grado di spingere / pop / shift elementi all'interno di un array e desidera che l'array sia archiviato in localStorage o effettivamente sessionStorage, ecco qui:

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

esempio di utilizzo - memorizzazione di stringhe semplici nell'array localStorage:

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

esempio di utilizzo - memorizzazione di oggetti nell'array sessionStorage:

var item1 = {}; item1.name = 'fred'; item1.age = 48;
sessionStorage.pushArrayItem('myArray',item1);

var item2 = {}; item2.name = 'dave'; item2.age = 22;
sessionStorage.pushArrayItem('myArray',item2);

metodi comuni per manipolare le matrici:

.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

Questo è un set di metodi molto utile per manipolare array archiviati in localStorage o sessionStorage e merita molto più credito di quanto non sia attratto. @Andy Lorenz Grazie per aver dedicato del tempo per condividere!
Velojet,



6

È possibile utilizzare localDataStorage per archiviare in modo trasparente tipi di dati javascript (Array, Boolean, Date, Float, Integer, String e Object). Fornisce inoltre una leggera offuscamento dei dati, comprime automaticamente le stringhe, facilita la query per chiave (nome) e la query per valore (chiave) e aiuta a imporre l'archiviazione condivisa segmentata all'interno dello stesso dominio mediante il prefisso delle chiavi.

[DISCLAIMER] Sono l'autore dell'utilità [/ DISCLAIMER]

Esempi:

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

Come puoi vedere, i valori primitivi sono rispettati.


1
Questa è una risorsa geniale e proprio quello di cui ho bisogno. Sto facendo app ioniche con AngularJS dove ho bisogno di salvare alcuni oggetti javascript in localStorage e fino a questo punto ho appena fatto JSON.parse e JSON.stringify, e funzionano, ma è un po 'più ingombrante di poterlo fare per usare solo un'utilità come questa. Lo proverò.
Nmuta,

4

Un'altra opzione sarebbe quella di utilizzare un plugin esistente.

Ad esempio persisto è un progetto open source che fornisce un'interfaccia semplice a localStorage / sessionStorage e automatizza la persistenza per i campi modulo (input, pulsanti di opzione e caselle di controllo).

caratteristiche persisto

(Dichiarazione di non responsabilità: sono l'autore.)


Continuo a lavorare sul mio file Leggimi, ma la mia versione non richiede jQuery, come sembra persisto, ma fornisce un'alternativa per gestire gli oggetti jQuery Element. Ne aggiungerò altre nel prossimo futuro, mentre ci lavoro di più, per aiutarlo a gestire ulteriormente diversi oggetti jQuery e mantenere cose come i dati persistenti. Inoltre, +1 per aver cercato di fornire una soluzione più semplice! Inoltre, utilizza tutti i metodi tradizionali di localStroage; exp: var lsh = new localStorageHelper(); lsh.setItem('bob', 'bill'); include anche eventi.
SpYk3HH,

4

Puoi usare ejson per memorizzare gli oggetti come stringhe.

EJSON è un'estensione di JSON per supportare più tipi. Supporta tutti i tipi sicuri per JSON, nonché:

Tutte le serializzazioni EJSON sono anche JSON valide. Ad esempio un oggetto con una data e un buffer binario verrebbe serializzato in EJSON come:

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

Ecco il mio wrapper localStorage che usa ejson

https://github.com/UziTech/storage.js

Ho aggiunto alcuni tipi al mio wrapper tra cui espressioni e funzioni regolari


2

Ho realizzato un altro wrapper minimalista con solo 20 righe di codice per consentirne l'utilizzo come dovrebbe:

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

Per gli utenti Typescript disposti a impostare e ottenere proprietà digitate:

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

Esempio di utilizzo :

// 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 è uno strato di zucchero LocalStorage che ti consente di scrivere cose del genere:

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

Non utilizza JSON.stringify / parse perché sarebbe inaccurato e lento su oggetti di grandi dimensioni. Al contrario, ogni valore di terminale ha la propria voce localStorage.

Probabilmente puoi immaginare che potrei avere qualcosa a che fare con rhaboo.


1

Ecco una versione estesa del codice pubblicato da @danott

Implementerà anche il valore di eliminazione dal localstorage e mostrerà come aggiungere un livello Getter e Setter al posto di

localstorage.setItem(preview, true)

tu puoi scrivere

config.preview = true

Va bene qui andiamo:

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

Bene, puoi rimuovere la parte degli alias .bind(...). Tuttavia, l'ho appena inserito poiché è davvero bello saperlo. Mi ci sono volute ore per scoprire perché un semplice get = localStorage.getItem;non funziona


1

Ho fatto una cosa che non rompe gli oggetti di archiviazione esistenti, ma crea un wrapper in modo da poter fare quello che vuoi. Il risultato è un oggetto normale, senza metodi, con accesso come qualsiasi oggetto.

La cosa che ho fatto.

Se vuoi che 1 localStorageproprietà sia magica:

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

Se hai bisogno di più:

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

Tutto ciò che fai propo gli oggetti all'interno storage verranno automaticamente salvati localStorage. Giochi sempre con un oggetto reale, quindi puoi fare cose come questa:

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

E ogni nuovo oggetto all'interno di un oggetto tracciato verrà automaticamente rintracciato.

Il rovescio della medaglia molto grande: dipende da Object.observe()quindi ha un supporto del browser molto limitato. E non sembra che arriverà presto per Firefox o Edge.


1

Non è possibile memorizzare il valore chiave senza Formato stringa .

LocalStorage supporta solo il formato String per chiave / valore.

Ecco perché dovresti convertire i tuoi dati in stringa qualunque sia Array o Object .

Per archiviare i dati in localStorage, prima di tutto stringere il codice usando il metodo JSON.stringify () .

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

Quindi, quando si desidera recuperare i dati, è necessario analizzare nuovamente String to Object.

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

Spero che sia d'aiuto.


0

Per memorizzare un oggetto, è possibile creare lettere che è possibile utilizzare per ottenere un oggetto da una stringa a un oggetto (potrebbe non avere senso). Per esempio

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

Questa tecnica causerà alcuni difetti se usi la lettera che hai usato per dividere l'oggetto, ed è anche molto sperimentale.


0

Ho trovato un modo per farlo funzionare con oggetti che hanno riferimenti ciclici.

Facciamo un oggetto con riferimenti ciclici.

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;

Non possiamo fare JSON.stringifyqui, a causa dei riferimenti circolari.

circularUncle

LOCALSTORAGE.CYCLICJSONha .stringifye .parseproprio come normale JSON, ma funziona con oggetti con riferimenti circolari. ("Opere" significa analisi (stringify (obj)) e obj sono profondamente uguali E hanno identici insiemi di "uguaglianze interne")

Ma possiamo semplicemente usare le scorciatoie:

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

Quindi, recoveredsarà "lo stesso" per obj, nel senso seguente:

[
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
]

Ecco l'implementazione di 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 ('user', JSON.stringify (user));

Quindi per recuperarlo dall'archivio e convertirlo di nuovo in un oggetto:

var user = JSON.parse (localStorage.getItem ('user'));

Se abbiamo bisogno di eliminare tutte le voci del negozio, possiamo semplicemente fare:

localStorage.clear ();


3
Questa è una domanda di 10 anni. Pensi che la tua risposta aggiunga qualcosa che non è già coperto dalle altre risposte?
Kristopher Johnson,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.