javascript - localstorage - sessionstorage jquery




Stockage d'objets dans le stockage local HTML5 (18)

Stringify ne résout pas tous les problèmes

Il semble que les réponses ici ne couvrent pas tous les types possibles en JavaScript, voici donc quelques exemples pour vous aider à les traiter correctement:

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

Je ne recommande pas de stocker des fonctions, car eval() est une mauvaise chose qui peut entraîner des problèmes de sécurité, d’optimisation et de débogage. En général, eval() ne devrait jamais être utilisé dans le code JavaScript.

Membres privés

Le problème JSON.stringify() utilisation de JSON.stringify() pour stocker des objets est que cette fonction ne peut pas sérialiser les membres privés. Ce problème peut être résolu en écrasant la méthode .toString() (appelée implicitement lors du stockage de données dans le stockage 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);

Références circulaires

Un autre problème que stringify ne peut pas traiter concerne les références circulaires:

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

Dans cet exemple, JSON.stringify() TypeError une TypeError "Conversion de structure circulaire en JSON" . Si le stockage des références circulaires doit être pris en charge, le deuxième paramètre de JSON.stringify() peut être utilisé:

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

Cependant, trouver une solution efficace pour stocker des références circulaires dépend fortement des tâches à résoudre, et la restauration de telles données n'est pas non plus triviale.

Il existe déjà une question sur le SO qui traite de ce problème: Stringify (convertir en JSON) un objet JavaScript avec une référence circulaire

J'aimerais stocker un objet JavaScript dans HTML5 localStorage , mais mon objet est apparemment converti en chaîne.

Je peux stocker et récupérer des types et des tableaux JavaScript primitifs à l'aide de localStorage , mais les objets ne semblent pas fonctionner. Devraient-ils?

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

La sortie de la console est

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

Il me semble que la méthode setItem convertit l’entrée en chaîne avant de la stocker.

Je constate ce comportement dans Safari, Chrome et Firefox. J'imagine donc que c'est une mauvaise compréhension de la spécification HTML5 Web Storage et non d'un bogue ou d'une limitation propre au navigateur.

J'ai essayé de donner un sens à l'algorithme de clone structuré décrit dans http://www.w3.org/TR/html5/infrastructure.html . Je ne comprends pas tout à fait ce que ça dit, mais peut-être que mon problème est lié au fait que les propriétés de mon objet ne sont pas énumérables (???)

Existe-t-il une solution de contournement facile?

Mise à jour: le W3C a finalement changé d'avis sur la spécification des clones structurés et a décidé de modifier les spécifications pour les faire correspondre aux implémentations. Voir https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111 . Donc, cette question n’est plus valable à 100%, mais les réponses pourraient quand même vous intéresser.


Amélioration de la réponse de @Guria:

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


Storage.prototype.getObject = function (key) {
    var value = this.getItem(key);
    try {
        return JSON.parse(value);
    }
    catch(err) {
        console.log("JSON parse failed for lookup of ", key, "\n error was: ", err);
        return null;
    }
};

En théorie, il est possible de stocker des objets avec des fonctions:

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

Cependant, la sérialisation / désérialisation des fonctions n'est pas fiable car elle dépend de la mise en œuvre .



J'ai créé quelque chose qui ne casse pas les objets de stockage existants, mais crée un wrapper afin que vous puissiez faire ce que vous voulez. Le résultat est un objet normal, pas de méthode, avec un accès comme n'importe quel objet.

La chose que j'ai faite.

Si vous voulez localStorage propriété localStorage soit magique:

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

Si vous avez besoin de plusieurs:

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

Tout ce que vous faites pour prop , ou les objets dans le storage seront automatiquement sauvegardés dans localStorage . Vous jouez toujours avec un objet réel, vous pouvez donc faire des choses comme celle-ci:

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

Et chaque nouvel objet à l' intérieur d' un objet suivi sera automatiquement suivi.

Le très gros inconvénient: cela dépend de Object.observe() sorte que la prise en charge du navigateur est très limitée. Et il ne semble pas que ce soit pour Firefox ou Edge de si tôt.


J'ai créé un autre wrapper minimaliste avec seulement 20 lignes de code pour permettre de l'utiliser comme il se doit:

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


Je suis arrivé à ce message après avoir cliqué sur un autre message qui a été fermé en tant que duplicata de celui-ci - intitulé "Comment stocker un tableau dans le stockage local?". Ce qui est correct, sauf qu'aucun fil ne fournit en réalité une réponse complète quant à la manière de gérer un tableau dans localStorage. Cependant, j'ai réussi à concevoir une solution basée sur les informations contenues dans les deux threads.

Donc, si quelqu'un d'autre veut pouvoir pousser / sauter / décaler des éléments dans un tableau et qu'il veut que ce tableau soit stocké dans localStorage ou même dans sessionStorage, voici ce que vous devez faire:

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

exemple d'utilisation - stockage de chaînes simples dans un tableau localStorage:

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

exemple d'utilisation - stockage d'objets dans le tableau 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);

méthodes courantes pour manipuler des tableaux:

.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

L'extension de l'objet Storage est une solution géniale. Pour mon API, j'ai créé une façade pour localStorage, puis je vérifie s'il s'agit d'un objet ou non lors de la configuration et de l'obtention.

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

Une amélioration mineure sur une 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);
}

En raison de l' évaluation du court-circuit , getObject() retournera immédiatement la valeur null si la key n'est pas dans Storage. De plus, il ne lancera pas d'exception SyntaxError si value est "" (la chaîne vide; JSON.parse() ne peut pas gérer cela).


Une autre option serait d'utiliser un plugin existant.

Par exemple, persisto est un projet open source qui fournit une interface simple à localStorage / sessionStorage et automatise la persistance des champs de formulaire (entrée, boutons radio et cases à cocher).

(Avertissement: je suis l'auteur.)


Voici une version étendue du code posté par @danott

Cela implémentera également la valeur delete de localstorage et montrera comment ajouter une couche Getter et Setter

localstorage.setItem(preview, true)

tu peux écrire

config.preview = true

Ok, voilà où sont allés:

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

Eh bien, vous pouvez .bind(...) les alias avec .bind(...) . Cependant, je viens de le mettre car c'est vraiment bon de savoir à ce sujet. Je m’ai pris des heures pour savoir pourquoi un simple get = localStorage.getItem; ne fonctionne pas


Vous feriez mieux de créer des fonctions comme setter et getter sur localStorage . Ainsi, vous aurez un meilleur contrôle et vous ne devrez pas répéter l'analyse JSON, etc. il va même gérer votre ("") chaîne vide clé / cas de données en douceur.

function setItemInStorage(dataKey, data){
    localStorage.setItem(dataKey, JSON.stringify(data));
}

function getItemFromStorage(dataKey){
    var data = localStorage.getItem(dataKey);
    return data? JSON.parse(data): null ;
}

setItemInStorage('user', { name:'tony stark' });
getItemFromStorage('user'); /* return {name:'tony stark'} */

Vous pouvez utiliser ejson pour stocker les objets sous forme de chaînes.

EJSON est une extension de JSON qui prend en charge plusieurs types. Il prend en charge tous les types JSON-safe, ainsi que:

  • Date (Date JavaScript)
  • Binaire (JavaScript Uint8Array ou le résultat de EJSON.newBinary )
  • Types définis par l'utilisateur (voir EJSON.addType . Par exemple, Mongo.ObjectID est implémenté de cette façon.)

Toutes les sérialisations EJSON sont également des JSON valides. Par exemple, un objet avec une date et un tampon binaire serait sérialisé dans EJSON en tant que:

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

Voici mon wrapper localStorage utilisant ejson

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

J'ai ajouté quelques types à mon emballage, notamment des expressions régulières et des fonctions.


Vous pouvez utiliser localDataStorage pour stocker de manière transparente des types de données javascript (Array, Boolean, Date, Float, Integer, String et Object). Il fournit également une obfuscation de données légère, compresse automatiquement les chaînes, facilite la requête par clé (nom) ainsi que la requête par clé (clé), et aide à appliquer le stockage partagé segmenté au sein du même domaine en préfixant les clés.

[DISCLAIMER] Je suis l'auteur de l'utilitaire [/ DISCLAIMER]

Exemples:

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

Comme vous pouvez le constater, les valeurs primitives sont respectées.


http://rhaboo.org est une couche de sucre LocalStorage qui vous permet d'écrire des choses comme celle-ci:

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

Il n'utilise pas JSON.stringify / parse car cela serait inexact et lent sur les gros objets. Au lieu de cela, chaque valeur de terminal a sa propre entrée localStorage.

Vous pouvez probablement deviner que je pourrais avoir quelque chose à voir avec rhaboo ;-)

Adrian.


Regarde ça

Disons que vous avez le tableau suivant appelé films:

var movies = ["Reservoir Dogs", "Pulp Fiction", "Jackie Brown", 
              "Kill Bill", "Death Proof", "Inglourious Basterds"];

À l'aide de la fonction stringify, votre tableau de films peut être transformé en chaîne en utilisant la syntaxe suivante:

localStorage.setItem("quentinTarantino", JSON.stringify(movies));

Notez que mes données sont stockées sous la clé appelée quentinTarantino.

Récupération de vos données

var retrievedData = localStorage.getItem("quentinTarantino");

Pour reconvertir une chaîne en objet, utilisez la fonction d'analyse JSON:

var movies2 = JSON.parse(retrievedData);

Vous pouvez appeler toutes les méthodes de la matrice sur vos films2


Je pense que pour éviter ce genre de problème sur les cookies locaux, de session, vous pouvez utiliser la bibliothèque opendb ..

Ex. Dans lequel vous pouvez résoudre ceci en utilisant cet extrait

// for set object in db
db.local.setJSON("key", {name: "xyz"});  

// for get object form db
db.local.getJSON("key");

https://github.com/pankajbisht/openDB

Pour plus de détails sur le stockage Web, vous pouvez lire un article sur le stockage Web .


Un petit exemple de bibliothèque qui utilise localStorage pour garder une trace des messages reçus de contacts:

// This class is supposed to be used to keep a track of received message per contacts.
// You have only four methods:

// 1 - Tells you if you can use this library or not...
function isLocalStorageSupported(){
    if(typeof(Storage) !== "undefined" && window['localStorage'] != null ) {
         return true;
     } else {
         return false;
     }
 }

// 2 - Give the list of contacts, a contact is created when you store the first message
 function getContacts(){
    var result = new Array();
    for ( var i = 0, len = localStorage.length; i < len; ++i ) {
        result.push(localStorage.key(i));
    }
    return result;
 }

 // 3 - store a message for a contact
 function storeMessage(contact, message){
    var allMessages;
    var currentMessages = localStorage.getItem(contact);
    if(currentMessages == null){
        var newList = new Array();
        newList.push(message);
        currentMessages = JSON.stringify(newList);
    }
    else
    {
        var currentList =JSON.parse(currentMessages);
        currentList.push(message);
        currentMessages = JSON.stringify(currentList);
    }
    localStorage.setItem(contact, currentMessages);
 }

 // 4 - read the messages of a contact
 function readMessages(contact){

    var result = new Array();
    var currentMessages = localStorage.getItem(contact);

    if(currentMessages != null){
        result =JSON.parse(currentMessages);
    }
    return result;
 }




local-storage