Je voudrais stocker un objet JavaScript dans le localStorage
de HTML5, mais mon objet est apparemment converti en chaîne.
Je peux stocker et récupérer des types JavaScript primitifs et des tableaux à l'aide de localStorage
, mais les objets ne semblent pas fonctionner. Le 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 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 une chaîne de caractères avant de la stocker.
Je constate ce comportement dans Safari, Chrome et Firefox. Je suppose donc qu'il s'agit d'une mauvaise compréhension de la spécification [HTML5 Web Storage] (http://www.w3.org/TR/webstorage/) et non d'un bogue ou d'une limitation propre à un navigateur.
J'ai essayé de comprendre l'algorithme du clone structuré décrit dans http://www.w3.org/TR/html5/infrastructure.html. Je ne comprends pas bien ce qu'il 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 un moyen simple de contourner le problème ?
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.
En consultant la documentation de [Apple][1], [Mozilla][2] et [Mozilla again][3], la fonctionnalité semble se limiter à la gestion des paires clé/valeur de type chaîne.
Une solution de contournement peut consister à [stringifier][4] votre objet avant de le stocker, puis à l'analyser lorsque vous le récupérez :
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));
[1] : https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/Name-ValueStorage/Name-ValueStorage.html [2] : https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API [3] : https://developer.mozilla.org/en-US/docs/Web/API/Storage/setItem [4] : https://www.w3schools.com/js/js_json_stringify.asp
Une amélioration mineure par rapport à une 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 cause de l'évaluation en circuit court, getObject()
retournera immédiatement null
si key
n'est pas dans Storage. Il ne lèvera pas non plus d'exception SyntaxError
si value
est ""
(la chaîne vide ; JSON.parse()
ne peut pas gérer cela).
Vous pouvez trouver utile d'étendre l'objet Storage avec ces méthodes pratiques :
Storage.prototype.setObject = function(key, value) {
this.setItem(key, JSON.stringify(value));
}
Storage.prototype.getObject = function(key) {
return JSON.parse(this.getItem(key));
}
De cette façon, vous obtenez la fonctionnalité que vous vouliez vraiment, même si l'API ne prend en charge que les chaînes de caractères.