Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to store a javascript function in JSON

I have a JS object I would like to save in Local Storage for future use, and I cannot parse it to a string.

Code:

JSON.stringify({     a: 5,     b: function (param) {         return param;     } }) 

Result:

"{"a":5}" 

How do I save it for future use, if not with JSON?

(And creating my own Lexer-Parser to interupt string function I dont think is an option)

like image 481
Amit Avatar asked Apr 09 '16 13:04

Amit


People also ask

Can you store function in JSON?

In the general case, you can't. One reason is that a function usually needs the enclosing scope where it can find some of the variables it uses. In very specific cases you can use the Function constructor.

Can you put JavaScript in JSON?

JSON FormatJSON's format is derived from JavaScript object syntax, but it is entirely text-based. It is a key-value data format that is typically rendered in curly braces.

What does JSON () do in JavaScript?

json() The json() method of the Response interface takes a Response stream and reads it to completion. It returns a promise which resolves with the result of parsing the body text as JSON .


2 Answers

I'd recommend this approach:

Store arguments and the body in your json:

{"function":{"arguments":"a,b,c","body":"return a*b+c;"}} 

Now parse json and instantiate the function:

var f = new Function(function.arguments, function.body); 

I think it's save

like image 191
Kostiantyn Avatar answered Sep 24 '22 14:09

Kostiantyn


Usually a question like this indicates an X/Y problem: You need to do X, you think Y will help you do that, so you try to do Y, can't, and ask how to do Y. It would frequently be more useful to ask how to do X instead.

But answering the question asked: You could use replacer and reviver functions to convert the function to a string (during stringify) and back into a function (during parse) to store a string version of the function, but there are all sorts of issues with doing that, not least that the scope in which the function is defined may well matter to the function. (It doesn't matter to the function you've shown in the question, but I assume that's not really representative.) And converting a string from local storage into code you may run means that you are trusting that the local storage content hasn't been corrupted in a malicious way. Granted it's not likely unless the page is already vulnerable to XSS attacks, but it's an issue to keep in mind.

Here's an example, but I don't recommend it unless other options have been exhausted, not least because it uses eval, which (like its close cousin new Function)) can be a vector for malicious code:

// The object  var obj = {      a: 5,      b: function (param) {          return param;      }  };    // Convert to JSON using a replacer function to output  // the string version of a function with /Function(  // in front and )/ at the end.  var json = JSON.stringify(obj, function(key, value) {    if (typeof value === "function") {      return "/Function(" + value.toString() + ")/";    }    return value;  });    // Convert to an object using a reviver function that  // recognizes the /Function(...)/ value and converts it  // into a function via -shudder- `eval`.  var obj2 = JSON.parse(json, function(key, value) {    if (typeof value === "string" &&        value.startsWith("/Function(") &&        value.endsWith(")/")) {      value = value.substring(10, value.length - 2);      return (0, eval)("(" + value + ")");    }    return value;  });  document.body.innerHTML = obj2.b(42);

The construct (0, eval)("(" + value + ")"); ensures that eval runs at global scope rather than within the scope of the reviver function. Normally eval has a magic ability to use the scope you call it in, but that only works when you call it directly. Indirect eval as shown (or just var e = eval; e("(" + value + ")");) doesn't have that magic ability, it runs at global scope.

like image 26
T.J. Crowder Avatar answered Sep 23 '22 14:09

T.J. Crowder