Мы используем необязательный второй replacer аргумент JSON.stringify
ключевых предобработку/значения, излучающие функции в строковой форме:
function stringify_with_fns(obj) {
return JSON.stringify(obj, function(key, value) {
return typeof value === "function" ? value.toString() : value;
});
}
Затем, чтобы превратить строковую функцию обратно в реальные функции на выходе, мы используем необязательный второй параметр 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;
}
});
}
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;}
Обратите внимание, что поскольку функции, созданные new Function
, все находятся в глобальном масштабе, они потеряют свой охват и закрытие.
Остается вопрос, полезен ли этот вопрос. Я полагаю, что это может быть для небольших функций полезности.
Расширение концепции сериализации/десериализации регулярных выражений или объектов даты остается в качестве упражнения.
Интересно ... но я не могу себе представить, что есть способ фактически получить код в теле функции как строку. Но я могу ошибаться, и если есть способ, это было бы потрясающе :) – 2010-11-27 20:36:55
А? Там _is_ такой способ: что вызов myfunc.toString() не вышел из ниоткуда: P https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/toString Проблема не в том, что функция кода, но довольно элегантно подставляя ему значение полей без искажения анализатора JSON. – dpq 2010-11-27 20:45:28