2

I have an array of objects and each of these objects have a function, for example:

var array = [];
var object = {
    param1: 0,
    param2: 0,
    function1: function(){
        param1 += 1;
    },
    function2: function(){
        param2 = new Date().getTime();
    }
}
for(var i=0; i<5; i++){
    array.push(object);
}

Then I want to convert this array to JSON and preserve the functions, so I do the following:

var json = JSON.stringify(array, function(key, val){
    if(typeof(val) === "function"){
        return val.toString();
    }else{
        return val;
    }
});

Then I want to get the array with my objects back, so I do the following:

var newArray = JSON.parse(json);

But my problem starts here. The function that I saved in JSON variable were converted to strings, so I can't run it for example:

alert(newArray[0].param1); //It return 0
newArray[0].function1();  //It says "Uncaught TypeError: string is not a function"
alert(newArray[0].param1); //Do not show anything

How can I solve this? How can I run this function? I tried to use eval() without no success. I would like to solve it without jQuery or any plugins.

Peter O.
  • 32,158
  • 14
  • 82
  • 96
Daniel Oliveira
  • 1,280
  • 14
  • 36
  • 2
    please, [take a look](http://stackoverflow.com/questions/3946958/pass-function-in-json-and-execute) – Sergey Aug 03 '14 at 01:04
  • This will never work. Even if you could the function, you won't be able to reconstruct the captures that they use. – Raymond Chen Aug 03 '14 at 01:05
  • `new Function()` https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function – epascarello Aug 03 '14 at 01:15

2 Answers2

4

This might help you:

When deserializing the function you have to instatiate it with new Function(arguments, functionBody);.

For example:

var func = function(a, b) {
    return a * b;
};
var funcStr = func.toString();
// From http://stackoverflow.com/questions/14885995/how-to-get-a-functionss-body-as-string
var funcBody = funcStr.match(/function[^{]+\{([\s\S]*)\}$/)[1];
var newFunc = new Function(['a', 'b'], funcBody);
alert(newFunc(4, 3));

Functions are pretty complex objects (especially because of variable scopes and closures), so unless you're serializing simple functions, this might give you unexpected results.

Christophe L
  • 13,725
  • 6
  • 33
  • 33
0

You can't call a String because a String is not a Function. String may be called if you use a eval function, but It seems not to be final answer for your wanting to know.

    var object = {
        param1: 0,
        param2: 0,
        function1: "param1 += 1;",
        function2: "param2 = new Date().getTime();"
    };

Unfortunately, this code has a binding problem. params can not be found since eval has a different context.


There's an excellent answer Christophe L has commented above. I think that we can clear eval context problem, getting some minor editing to do.

All that we have to do is get the context of newFunc to be bound object. You can see it on the following code

    var array = [];
    var object = {
        param1: 0,
        param2: 0,
        function1: function(){
            this.param1 += 1;
        },
        function2: function(){
            this.param2 = new Date().getTime();
        }
    };
    for(var i=0; i<5; i++){
        array.push(object);
    }

    var json = JSON.stringify(array, function(key, val){
        if(typeof(val) === "function"){
            return val.toString();
        }else{
            return val;
        }
    });

    var newArray = JSON.parse(json);

    var funcStr = newArray[0].function1.toString();
    // From http://stackoverflow.com/questions/14885995/how-to-get-a-functionss-body-as-string
    var funcBody = funcStr.match(/function[^{]+\{([\s\S]*)\}$/)[1];
    var newFunc = new Function('jsonFunc', funcBody);

    newFunc.apply(object);
    console.log(object.param1);
KimCoding
  • 71
  • 8