dpq*_*dpq 4 javascript parsing json
假设您有以下内容:
function myfunc() {
// JS code
}
var args = '{ "strfield": "hello world", "numfield": 10, "funcfield": myfunc }';
Run Code Online (Sandbox Code Playgroud)
问题:如何在将args变量提交给JSON解析器之前处理变量,以便将myfunc其替换为myfunc.toString()(即函数体)的结果?建议的解决方案应该适用于任意函数和这样的准JSON字符串.
小智 6
我们使用可选的第二个replacer参数来JSON.stringify预处理键/值,以字符串形式发出函数:
function stringify_with_fns(obj) {
return JSON.stringify(obj, function(key, value) {
return typeof value === "function" ? value.toString() : value;
});
}
Run Code Online (Sandbox Code Playgroud)
然后在出路时将字符串化函数转换回实际函数,我们使用可选的第二个reviver参数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;
}
});
}
Run Code Online (Sandbox Code Playgroud)
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);
}
Run Code Online (Sandbox Code Playgroud)
为了避免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);
}
Run Code Online (Sandbox Code Playgroud)
测试:
x = parse_with_fns(stringify_with_fns({a: function() {var x=1;}}))
x.a
> function anonymous() {var x=1;}
Run Code Online (Sandbox Code Playgroud)
但请注意,由于创建的函数new Function都在全局范围内,因此它们将失去其封闭范围和闭包.
唯一剩下的问题是这是否有用.我想它可能适用于小型实用功能.
将概念扩展为序列化/反序列化正则表达式或日期对象仍然是一个练习.