假设您有以下内容:
function myfunc() {
// JS code
}
var args = '{ "strfield": "hello world", "numfield": 10, "funcfield": myfunc }';
问题:如何在将args
变量提交给JSON解析器之前对其进行处理,以便myfunc
替换为myfunc.toString()
的结果(即,{{1}}的正文。功能)?建议的解决方案应该适用于任意函数和这样的准JSON字符串。
答案 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);