J'aimerais stocker un objet JavaScript en HTML5 localStorage
, mais mon objet est apparemment en train d'être converti en chaîne.
Je peux stocker et récupérer des types et des tableaux JavaScript primitifs à l'aide 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 setItem
méthode convertit l'entrée en chaîne avant de la stocker.
Je vois ce comportement dans Safari, Chrome et Firefox, donc je suppose que c'est ma mauvaise compréhension de la spécification HTML5 Web Storage , pas un bug ou une limitation spécifique au navigateur.
J'ai essayé de comprendre l' algorithme de clone structuré décrit dans http://www.w3.org/TR/html5/infrastructure.html . Je ne comprends pas bien ce qu'il dit, mais mon problème est peut-être 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 du clone structuré et a décidé de modifier la spécification pour qu'elle corresponde aux implémentations. Voir https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111 . Cette question n'est donc plus valable à 100%, mais les réponses peuvent toujours être intéressantes.
la source
Réponses:
En regardant à nouveau Apple , Mozilla et Mozilla documentation , la fonctionnalité semble être limitée pour gérer uniquement les paires clé / valeur de chaîne.
Une solution de contournement peut être de filtrer votre objet avant de le stocker, puis de l'analyser ultérieurement lorsque vous le récupérez:
la source
JSON.stringify()
étend l'objet référencé à son "contenu" complet (implicitement stringifié) dans l'objet que nous stringifions. Voir: stackoverflow.com/a/12659424/2044940Une amélioration mineure sur une variante :
En raison de l' évaluation de court-circuit ,
getObject()
va immédiatement revenirnull
sikey
n'est pas dans le stockage. Il ne lèvera pas non plus d'SyntaxError
exception ifvalue
is""
(la chaîne vide;JSON.parse()
ne peut pas gérer cela).la source
var userObject = { userId: 24, name: 'Jack Bauer' };
Et pour la définirlocalStorage.setObject('user', userObject);
Ensuite, récupérez-la du stockageuserObject = localStorage.getObject('user');
Vous pouvez même stocker un tableau d'objets si vous le souhaitez.key
n'est pas dans le stockage local,window.localStorage.getItem(key)
retournenull
- il ne lève pas d' exception "Accès illégal" - etJSON.parse(null)
retournenull
également - il ne lève pas non plus d'exception, ni dans Chromium 21 ni dans ES 5.1 section 15.12.2 , carString(null) === "null"
qui peut être interprété comme un littéral JSON .""
(la chaîne vide) avant. Parce qu'il convertit en typefalse
etJSON.parse("")
, ce quiSyntaxError
déclencherait une exception, n'est pas appelé.Vous pourriez trouver utile d'étendre l'objet Storage avec ces méthodes pratiques:
De cette façon, vous obtenez les fonctionnalités que vous vouliez vraiment, même si sous l'API ne prend en charge que les chaînes.
la source
localStorage.setObject
.getObject()
lèvera uneSyntaxError
exception si la valeur stockée est""
, carJSON.parse()
ne peut pas gérer cela. Voir ma modification de la réponse de Guria pour plus de détails.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.
la source
data.set('username': 'ifedi', 'fullname': { firstname: 'Ifedi', lastname: 'Okonkwo'});
:?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 sur la façon de les traiter correctement:
Je ne recommande pas de stocker des fonctions car le
eval()
mal peut entraîner des problèmes de sécurité, d'optimisation et de débogage. En général,eval()
ne doit jamais être utilisé dans du code JavaScript.Membres privés
Le problème avec l'utilisation
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 remplaçant la.toString()
méthode (qui est appelée implicitement lors du stockage de données dans le stockage Web):Références circulaires
Un autre problème
stringify
ne peut pas être résolu sont les références circulaires:Dans cet exemple,
JSON.stringify()
lancera uneTypeError
"Conversion de structure circulaire en JSON" . Si le stockage de références circulaires doit être pris en charge, le deuxième paramètre deJSON.stringify()
peut être utilisé:Cependant, trouver une solution efficace pour stocker des références circulaires dépend fortement des tâches à résoudre, et la restauration de ces données n'est pas non plus triviale.
Il y a déjà une question sur SO traitant de ce problème: Stringify (convertir en JSON) un objet JavaScript avec référence circulaire
la source
Il existe une excellente bibliothèque qui englobe de nombreuses solutions, elle prend même en charge les anciens navigateurs appelés jStorage
Vous pouvez définir un objet
Et récupérez-le facilement
la source
En théorie, il est possible de stocker des objets avec des fonctions:
Cependant, la sérialisation / désérialisation des fonctions n'est pas fiable car elle dépend de l'implémentation .
la source
c.f[k] = escape(a[k]);
par Unicode-safec.f[k] = encodeURIComponent(a[k]);
eteval('b.' + k + ' = ' + unescape(data.f[k]));
parb[k] = eval("(" + decodeURIComponent(data.f[k]) + ")");
. Les parenthèses sont obligatoires car votre fonction, si elle est sérialisée correctement, est susceptible d'être anonyme, ce qui n'est pas tel quel / Statement / (donceval()
) lèverait uneSyntaxError
exception sinon).typeof
est un opérateur , ne l'écrivez pas comme s'il s'agissait d'une fonction. Remplaceztypeof(a[k])
partypeof a[k]
.for
-in
n'a pas été filtré pour ses propres propriétés. 3. Le style de code, y compris le référencement, était incohérent.the use and placement of white space, line terminators, and semicolons within the representation String is implementation-dependent.
je ne vois aucune différence fonctionnelle.Note *in particular* that …
. Mais la spécification de la valeur de retour commence parAn implementation-dependent representation of the function is returned. This representation has the syntax of a FunctionDeclaration.
La valeur de retour peut êtrefunction foo () {}
- en supposant une implémentation conforme .Je suis arrivé à ce message après avoir cliqué sur un autre message qui a été fermé en double - intitulé `` comment stocker un tableau dans le stockage local? ''. Ce qui est bien, sauf qu'aucun des threads ne fournit réellement une réponse complète quant à la façon dont vous pouvez maintenir un tableau dans localStorage - cependant j'ai réussi à créer une solution basée sur les informations contenues dans les deux threads.
Donc, si quelqu'un d'autre veut pouvoir pousser / pop / shift des éléments dans un tableau, et qu'ils veulent que le tableau soit stocké dans localStorage ou même sessionStorage, vous allez ici:
exemple d'utilisation - stockage de chaînes simples dans un tableau localStorage:
exemple d'utilisation - stockage d'objets dans le tableau sessionStorage:
méthodes courantes pour manipuler les tableaux:
la source
Nous vous recommandons d'utiliser une bibliothèque d'abstraction pour de nombreuses fonctionnalités décrites ici ainsi qu'une meilleure compatibilité. Beaucoup d'options:
la source
Vous pouvez utiliser localDataStorage pour stocker de manière transparente les types de données javascript (tableau, booléen, date, flottant, entier, chaîne et objet). Il fournit également une obfuscation légère des données, comprime automatiquement les chaînes, facilite la requête par clé (nom) ainsi que la requête par (clé) valeur, et aide à appliquer le stockage partagé segmenté dans le même domaine en préfixant les clés.
[DISCLAIMER] Je suis l'auteur de l'utilitaire [/ DISCLAIMER]
Exemples:
Comme vous pouvez le voir, les valeurs primitives sont respectées.
la source
Une autre option serait d'utiliser un plugin existant.
Par exemple, persisto est un projet open source qui fournit une interface facile à localStorage / sessionStorage et automatise la persistance des champs de formulaire (entrée, boutons radio et cases à cocher).
(Avertissement: je suis l'auteur.)
la source
localStroage
; exp:var lsh = new localStorageHelper(); lsh.setItem('bob', 'bill');
comprend également les événements.Vous pouvez utiliser ejson pour stocker les objets sous forme de chaînes.
Voici mon wrapper localStorage utilisant ejson
https://github.com/UziTech/storage.js
J'ai ajouté quelques types à mon wrapper, y compris des expressions régulières et des fonctions
la source
J'ai fait un autre wrapper minimaliste avec seulement 20 lignes de code pour permettre de l'utiliser comme il se doit:
https://github.com/zevero/simpleWebstorage
la source
Pour les utilisateurs Typescript désireux de définir et d'obtenir des propriétés typées:
Exemple d'utilisation :
la source
https://github.com/adrianmay/rhaboo est une couche de sucre localStorage qui vous permet d'écrire des choses comme ceci:
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 le rhaboo.
la source
Voici une version étendue du code posté par @danott
Il va également mettre en œuvre suppression valeur de localStorage et montre comment ajoute une couche getter et setter donc au lieu de
localstorage.setItem(preview, true)
tu peux écrire
config.preview = true
D'accord, c'était parti:
Eh bien, vous pouvez supprimer la partie des alias
.bind(...)
. Cependant je viens de le mettre car c'est vraiment bon de savoir à ce sujet. J'ai mis des heures à découvrir pourquoi un simpleget = localStorage.getItem;
ne marche pasla source
J'ai créé une chose qui ne casse pas les objets de stockage existants, mais crée un wrapper pour que vous puissiez faire ce que vous voulez. Le résultat est un objet normal, sans méthodes, avec accès comme n'importe quel objet.
La chose que j'ai faite.
Si vous voulez que 1
localStorage
propriété soit magique:Si vous en avez besoin de plusieurs:
Tout ce que vous faites
prop
ou les objets à l' intérieurstorage
seront automatiquement enregistréslocalStorage
. Vous jouez toujours avec un vrai objet, vous pouvez donc faire des trucs comme ça:Et chaque nouvel objet à l' intérieur d' un objet suivi sera automatiquement suivi.
Le très gros inconvénient: cela dépend
Object.observe()
donc le support du navigateur est très limité. Et il ne semble pas que cela arrivera bientôt pour Firefox ou Edge.la source
Vous ne pouvez pas stocker de valeur de clé sans Format de chaîne .
LocalStorage ne prend en charge que le format String pour la clé / valeur.
C'est pourquoi vous devez convertir vos données en chaîne quel qu'il soit Tableau ou Objet .
Pour stocker des données dans localStorage, commencez par les filtrer en utilisant la méthode JSON.stringify () .
Ensuite, lorsque vous souhaitez récupérer des données, vous devez à nouveau analyser la chaîne en objet.
J'espère que cela aide.
la source
Pour stocker un objet, vous pouvez créer des lettres que vous pouvez utiliser pour obtenir un objet d'une chaîne vers un objet (cela peut ne pas avoir de sens). Par exemple
Cette technique provoquera quelques problèmes si vous utilisez la lettre que vous avez utilisée pour diviser l'objet, et elle est également très expérimentale.
la source
J'ai trouvé un moyen de le faire fonctionner avec des objets qui ont des références cycliques.
Faisons un objet avec des références cycliques.
Nous ne pouvons pas le faire
JSON.stringify
ici, à cause des références circulaires.LOCALSTORAGE.CYCLICJSON
a.stringify
et.parse
comme d'habitudeJSON
, mais fonctionne avec des objets avec des références circulaires. ("Works" signifie parse (stringify (obj)) et obj sont profondément égaux ET ont des ensembles identiques d '"égalités internes")Mais nous pouvons simplement utiliser les raccourcis:
Ensuite,
recovered
sera "le même" à obj, dans le sens suivant:Voici l'implémentation de
LOCALSTORAGE
la source
localStorage.setItem ('utilisateur', JSON.stringify (utilisateur));
Ensuite, pour le récupérer dans le magasin et le reconvertir en objet:
var user = JSON.parse (localStorage.getItem ('user'));
Si nous devons supprimer toutes les entrées du magasin, nous pouvons simplement faire:
localStorage.clear ();
la source