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