javascript - How to Store Objects in HTML5 localStorage?

ID : 219

viewed : 116

Tags : javascripthtmllocal-storagejavascript

Top 5 Answer for javascript - How to Store Objects in HTML5 localStorage?

vote vote

91

Looking at the Apple, Mozilla and Mozilla again documentation, the functionality seems to be limited to handle only string key/value pairs.

A workaround can be to stringify your object before storing it, and later parse it when you retrieve it:

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

82

A minor improvement on a 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); } 

Because of short-circuit evaluation, getObject() will immediately return null if key is not in Storage. It also will not throw a SyntaxError exception if value is "" (the empty string; JSON.parse() cannot handle that).

vote vote

73

You might find it useful to extend the Storage object with these handy methods:

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

This way you get the functionality that you really wanted even though underneath the API only supports strings.

vote vote

65

Creating a facade for the Storage object is an awesome solution, that way, you can implement your own get and set methods. For my API, I have created a facade for localStorage and then check if it is an object or not while setting and getting.

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

56

Stringify doesn't solve all problems

It seems that the answers here don't cover all types that are possible in JavaScript, so here are some short examples on how to deal with them correctly:

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

I do not recommend to store functions because eval() is evil can lead to issues regarding security, optimisation and debugging. In general, eval() should never be used in JavaScript code.

Private members

The problem with using JSON.stringify() for storing objects is, that this function can not serialise private members. This issue can be solved by overwriting the .toString() method (which is called implicitly when storing data in web storage):

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

Circular references

Another problem stringify can't deal with are circular references:

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

In this example, JSON.stringify() will throw a TypeError "Converting circular structure to JSON". If storing circular references should be supported, the second parameter of JSON.stringify() might be used:

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

However, finding an efficient solution for storing circular references highly depends on the tasks that need to be solved, and restoring such data is not trivial either.

There are already some question on SO dealing with this problem: Stringify (convert to JSON) a JavaScript object with circular reference

Top 3 video Explaining javascript - How to Store Objects in HTML5 localStorage?

Related QUESTION?