将函数序列化和反序列化为JSON

时间:2010-11-27 20:33:53

标签: javascript json parsing

假设您有以下内容:

function myfunc() {
  // JS code
}

var args = '{ "strfield": "hello world", "numfield": 10, "funcfield": myfunc }';

问题:如何在将args变量提交给JSON解析器之前对其进行处理,以便myfunc替换为myfunc.toString()的结果(即,{{1}}的正文。功能)?建议的解决方案应该适用于任意函数和这样的准JSON字符串。

2 个答案:

答案 0 :(得分:5)

我们使用JSON.stringify的可选第二个replacer参数来预处理键/值,以字符串形式发出函数:

function stringify_with_fns(obj) {
    return JSON.stringify(obj, function(key, value) {
        return typeof value === "function" ? value.toString() : value;
    });
}

然后在出路时将字符串化的函数转换回实际函数,我们使用可选的第二个reviver参数{} 1},如

JSON.parse

function parse_with_fns(json) { return JSON.parse(json, function(key, value) { if (looks_like_a_function_string(value)) { return make_function_from_string(value); } else { return value; } }); } 只是一个正则表达式,looks_like_a_function_string的第一个剪辑可以使用make_function_from_string

eval

为了避免function looks_like_a_function_string(value) { return /^function.*?\(.*?\)\s*\{.*\}$/.test(value); } function make_function_from_string(value) { return eval(value); } ,我们可以选择函数字符串来查找其参数和正文,因此我们可以将它们传递给eval

new Function

测试:

function make_function_from_string(value) {
    var args = value
        .replace(/\/\/.*$|\/\*[\s\S]*?\*\//mg, '') //strip comments
        .match(/\(.*?\)/m)[0]                      //find argument list
        .replace(/^\(|\)$/, '')                    //remove parens
        .match(/[^\s(),]+/g) || [],                //find arguments
        body = value.match(/\{(.*)\}/)[1]          //extract body between curlies

    return Function.apply(0, args.concat(body);
}

但请注意,由于x = parse_with_fns(stringify_with_fns({a: function() {var x=1;}})) x.a > function anonymous() {var x=1;} 创建的函数都在全局范围内,因此它们将失去其封闭范围和闭包。

唯一剩下的问题是这是否有用。我想它可能适用于小型实用功能。

将概念扩展为序列化/反序列化正则表达式或日期对象,这是一个练习。

答案 1 :(得分:-1)

喜欢这个?我必须更改它,因为你拥有的不是有效的JSON字符串,因为myfunc没有双引号。所以我添加了那些。

解析它,获取funcfield的值,找到函数(虽然它假定它在全局上下文中),调用toString()更新funcfield的值, - 将其设置为JSON。

示例: http://jsfiddle.net/patrick_dw/QUR6Z/

var myfunc = function() {
    alert('hi');
};

var args = '{ "strfield": "hello world", "numfield": 10, "funcfield": "myfunc" }';
var parsed = JSON.parse( args );

parsed.funcfield = window[parsed.funcfield].toString();
var stringified = JSON.stringify( parsed );

alert(stringified);

这是你的意思吗?


修改

我猜你可以使用当前的上下文,只要该上下文包含在拥有该函数的上下文中。

parsed.funcfield = this[parsed.funcfield].toString();

或者,如果您不能双重引用功能名称,则可以使用eval代替,如果您确定数据是安全的。

示例: http://jsfiddle.net/patrick_dw/QUR6Z/1/

var args = '{ "strfield": "hello world", "numfield": 10, "funcfield": myfunc }';
window.eval( 'var parsed = ' + args );

parsed.funcfield = parsed.funcfield.toString();
var stringified = JSON.stringify( parsed );

alert(stringified);