I'm working with some objects that contains a number of data to be displayed and manipulated from browser, and I want to save it in local storage.
In order to save objects I used JSON.stringify() so everything become text, and it works well
{
"bindingRef": [],
"primo": {
"name": "primo",
"modifiable": true,
"binded": false,
"isInteger": false,
"label": "Numero di Primi"
},
"secondo": {
"name": "secondo",
"modifiable": true,
"binded": false,
"isInteger": false,
"label": "Numero di Secondi"
}
}
Now I'm trying to save also a function by converting it to a string and then saveing it
JSON.stringify(myFunction.toString());
but the output is this
"savedFunction": "function () {\n\t\t\t\tvar tot = menu.primo.get() * 6 + menu.secondo.get() * 8 + menu.dolce.get() * 4;\n\t\t\t\tif (menu.sconto.get()) {\n\t\t\t\t\treturn tot * 0.90;\n\t\t\t\t} else {\n\t\t\t\t\treturn tot;\n\t\t\t\t}\n\t\t\t}"
Is it the correct way to save a function in local storage or is there a better way to do this? If this is the correct way, is there a way to simply remove any tabulation/indentation character or should I manipulate the string, for example using some regexp function?
Function in JS as in many functional languages are closures: they wrap inside them the content of the environment scope at the moment of definition, including ephemeral data like db or file handles.
It's not a good idea because this can lead to problems due to JSON deserialization behaviour, so you have to check what in the function is wrapped and what is self-defined.
See also this SO thread for further information.
You can put the function in an object and use the functions storage.set and storage.get that I created instead of localStorage.set and localStorage.get (localStorage doesn't allow functions to be added, unlike JSON).
storage.set will stringify an object including functions before using localStorage.setItem().
storage.get will parse an object including functions after using localStorage.getItem().
I modified the functions JSON.stringify and JSON.parse to be able to handle functions, so you can use it in other parts of your code without changing function names. I appended a 2 to the original functions, so I can use them within the updated functions.
JSON.stringify2 = JSON.stringify;
JSON.parse2 = JSON.parse;
JSON.stringify = function(value) {
return JSON.stringify2(value, function(key, val) {
return (typeof val === 'function') ? val.toString().replace(/\t|\n/g, '') : val;
});
}
JSON.parse = function(value) {
return JSON.parse2(value, function(key, val) {
if (typeof val === 'string') {
var regex = /^function\s*\([^()]*\)\s*{.*}$/;
if (regex.exec(val) !== null)
return eval('key = ' + val);
else
return val;
} else
return val;
});
}
var storage = {};
storage.set = function(key, value) {
if (typeof value === 'object')
value = JSON.stringify(value);
localStorage.setItem(key, value);
}
storage.get = function(key) {
var value = localStorage.getItem(key);
try {
return JSON.parse(value);
} catch (e) {
return value;
}
}