How can I serialize a function in JavaScript?

后端 未结 7 1113
Happy的楠姐
Happy的楠姐 2020-12-05 01:59

For example, say I have a function defined as follows:

function foo() {
  return \"Hello, serialized world!\";
}

I want to be able to seria

7条回答
  •  無奈伤痛
    2020-12-05 02:45

    I made this answer to address some pretty big flaws with the existing answers: .toString()/eval() and new Function() on their own wont work at all if your function uses this or named arguments (function (named, arg) {}), respectively.

    Using toJSON() below, all you need to do is call JSON.stringify() as usual on the function, and use Function.deserialise when parse()ing.

    The following wont work for concise functions (hello => 'there'), but for standard ES5 fat functions it'll return it as it was defined, closures notwithstanding of course. My other answer will work with all that ES6 goodness.


    Function.prototype.toJSON = function() {
        var parts = this
            .toString()
            .match(/^\s*function[^(]*\(([^)]*)\)\s*{(.*)}\s*$/)
        ;
        if (parts == null)
            throw 'Function form not supported';
    
        return [
            'window.Function',
            parts[1].trim().split(/\s*,\s*/),
            parts[2]
        ];
    };
    Function.deserialise = function(key, data) {
        return (data instanceof Array && data[0] == 'window.Function') ?
            new (Function.bind.apply(Function, [Function].concat(data[1], [data[2]]))) :
            data
        ;
    };
    

    Take a look at the DEMO

    At it's simplest:

    var test = function(where) { return 'hello ' + where; };
    test = JSON.parse(JSON.stringify(test), Function.deserialise);
    console.log(test('there'));
    //prints 'hello there'
    

    More usefully, you can serialise entire objects containing functions and pull them back out:

    test = {
      a : 2,
      run : function(x, y, z) { return this.a + x + y + z; }
    };
    var serialised = JSON.stringify(test);
    console.log(serialised);
    console.log(typeof serialised);
    
    var tester = JSON.parse(serialised, Function.deserialise);
    console.log(tester.run(3, 4, 5));
    

    Outputs:

    {"a":2,"run":["window.Function",["x","y","z"]," return this.a + x + y + z; "]}
    string
    14
    

    I didn't test older IE's, but it works on IE11, FF, Chrome, Edge.

    NB, the name of the function is lost, if you use that property then there's nothing you can do, really.
    You can change it to not use prototype easily, but that's for you to do if that's what you need.

提交回复
热议问题