7

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?

Naigel
  • 9,086
  • 16
  • 65
  • 106
  • You want to save object stringified or function signature ? What output are you expecting ? – Sarfraz Jun 16 '12 at 12:57
  • Why do you want to save a function? In my opinion there is no "correct" way to do this because it doesn't really make sense to do it at all. Assuming you do want to save the `.toString()` version of the function, why do you want to remove tabs (which you could do with `.replace()`)? – nnnnnn Jun 16 '12 at 12:58

2 Answers2

6

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.

Community
  • 1
  • 1
Vincenzo Maggio
  • 3,787
  • 26
  • 42
1

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;
    }
}
Naud
  • 11
  • 2