2010-11-27 2 views
3

Предположим, у вас есть следующие:сериализации и десериализации функции и из JSON

function myfunc() { 
    // JS code 
} 

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

Проблема: как вы обрабатываете переменную args перед подачей его в анализатор JSON, так что myfunc заменяется результатом myfunc.toString() (т. Е. Тело функции)? Предлагаемое решение должно работать над произвольными функциями и такими квази-JSON-строками.

+0

Интересно ... но я не могу себе представить, что есть способ фактически получить код в теле функции как строку. Но я могу ошибаться, и если есть способ, это было бы потрясающе :) – 2010-11-27 20:36:55

+0

А? Там _is_ такой способ: что вызов myfunc.toString() не вышел из ниоткуда: P https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/toString Проблема не в том, что функция кода, но довольно элегантно подставляя ему значение полей без искажения анализатора JSON. – dpq 2010-11-27 20:45:28

ответ

-1

Нравится? Я должен был изменить его, потому что то, что у вас есть, не является допустимой строкой JSON, поскольку myfunc не имеет двойных кавычек. Поэтому я добавил их.

Это разбирает его, получает значение funcfield, находит функцию (хотя предполагается, что в глобальном контексте), вызывает toString() обновление значения funcfield, повторное stringifies его в качестве 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); 

Было ли это то, что вы имели в виду?


EDIT:

Я думаю, вы могли бы использовать текущий контекст, до тех пор, как контекст содержится в контексте, которому принадлежит функция.

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); 
3

Мы используем необязательный второй 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, все находятся в глобальном масштабе, они потеряют свой охват и закрытие.

Остается вопрос, полезен ли этот вопрос. Я полагаю, что это может быть для небольших функций полезности.

Расширение концепции сериализации/десериализации регулярных выражений или объектов даты остается в качестве упражнения.

Смежные вопросы