Подтвердить что ты не робот

Есть ли возможность иметь функции сохранения JSON.stringify?

Возьмите этот объект:

x = {
 "key1": "xxx",
 "key2": function(){return this.key1}
}

Если я это сделаю:

y = JSON.parse( JSON.stringify(x) );

Тогда y вернет { "key1": "xxx" }. Можно ли что-либо сделать для передачи функций через stringify? Создание объекта с прикрепленными функциями возможно с помощью "ye goode olde eval()", но что с его упаковкой?

4b9b3361

Ответ 1

Вы не можете упаковывать функции, поскольку данные, которые они закрывают, не видны для любого сериализатора. Даже Mozilla uneval не может правильно упаковать блокировки.

Лучше всего использовать ревизор и замену.

http://developer.yahoo.com/yui/examples/json/json_freeze_thaw.html

Функция reviver, переданная JSON.parse, применяется ко всем парам ключ: значение в сыром разобранном объекте от самых глубоких ключей до самого высокого уровня. В нашем случае это означает, что имя и обнаруженные свойства будут переданы через reviver, а затем объект, содержащий эти ключи, будет передан.

Ответ 2

Я столкнулся с той же проблемой. Был еще один пост, похожий на ваш найденный json-stringify-function. для вас может быть полезно следующее:

var JSONfn;
if (!JSONfn) {
    JSONfn = {};
}

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

  JSONfn.parse = function(str) {
    return JSON.parse(str,function(key, value){
        if(typeof value != 'string') return value;
        return ( value.substring(0,8) == 'function') ? eval('('+value+')') : value;
    });
  }
}());

Код фрагмента, взятый из Вадима Кирюхина JSONfn.js или см. документацию на Домашняя страница

Ответ 3

Технически это не JSON, я тоже не могу себе представить, зачем вам это нужно, но попробуйте следующий взлом:

x.key2 = x.key2.toString();
JSON.stringify(x)  //"{"key1":"xxx","key2":"function (){return this.key1}"}"

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

Ответ 4

Насколько я знаю, нет библиотек сериализации, которые сохраняют функции - на любом языке. Сериализация - это то, что нужно для сохранения данных. Компиляция - это то, что нужно для сохранения функций.

Ответ 5

Да, вы можете сделать это с помощью плагина JSONfn.

Взгляните на http://www.eslinstructor.net/jsonfn/

Это именно то, что вы ищете.

Ответ 6

Кажется, что люди, приземляющиеся здесь, имеют дело со структурами, которые были бы действительными JSON, если бы не тот факт, что они содержат функции. Итак, как мы справляемся с строкой этих структур?

Я столкнулся с проблемой при написании script для изменения настроек RequireJS. Вот как я это сделал. Во-первых, есть немного кода ранее, который гарантирует, что заполнитель, используемый внутри (">>>F<<<"), не отображается как значение в конфигурации RequireJS. Очень маловероятно, чтобы это случилось, но лучше безопасно, чем жаль. Конфигурация входа считывается как объект JavaScript, который может содержать массивы, атомные значения, другие Object и функции. Это было бы прямо поддающимся сшиванию как JSON, если функции не присутствовали. Эта конфигурация представляет собой объект config в следующем коде:

// Holds functions we encounter.
var functions = [];
var placeholder = ">>>F<<<";

// This handler just records a function object in `functions` and returns the 
// placeholder as the value to insert into the JSON structure.
function handler(key, value) {
    if (value instanceof Function) {
        functions.push(value);
        return placeholder;
    }

    return value;
}

// We stringify, using our custom handler.    
var pre = JSON.stringify(config, handler, 4);

// Then we replace the placeholders in order they were encountered, with
// the functions we've recorded.
var post = pre.replace(new RegExp('"' + placeholder + '"', 'g'),
                       functions.shift.bind(functions));

Переменная post содержит окончательное значение. Этот код основан на том, что порядок, в котором handler вызывается, совпадает с порядком различных частей данных в конечном JSON. Я проверил 5-е издание ECMAScript, которое определяет алгоритм стробирования и не может найти случай, когда будет проблема с упорядочением. Если бы этот алгоритм должен был измениться в будущей редакции, исправление заключалось бы в использовании уникальных placholders для функции и использовании их для возврата к функциям, которые будут храниться в ассоциативном массиве, сопоставляя уникальные заполнители с функциями.

Ответ 7

Озорным, но эффективным способом было бы просто:

Function.prototype.toJSON = function() { return this.toString(); }

Хотя ваша реальная проблема (помимо модификации прототипа Function) была бы десериализацией без использования eval.

Ответ 8

Полностью можно создавать функции из строки без eval()

var obj = {a:function(a,b){
    return a+b;
}};

var serialized = JSON.stringify(obj, function(k,v){
    //special treatment for function types
    if(typeof v === "function")
        return v.toString();//we save the function as string
    return v;
});
/*output:
"{"a":"function (a,b){\n        return a+b;\n    }"}"
*/

теперь некоторая магия, чтобы превратить строку в функцию с помощью этой функции

var compileFunction = function(str){
    //find parameters
    var pstart = str.indexOf('('), pend = str.indexOf(')');
    var params = str.substring(pstart+1, pend);
    params = params.trim();

    //find function body
    var bstart = str.indexOf('{'), bend = str.lastIndexOf('}');
    var str = str.substring(bstart+1, bend);

    return Function(params, str);
}

теперь используйте JSON.parse с reviver

var revivedObj = JSON.parse(serialized, function(k,v){
    // there is probably a better way to determ if a value is a function string
    if(typeof v === "string" && v.indexOf("function") !== -1)
        return compileFunction(v);
    return v;
});

//output:

 revivedObj.a

 function anonymous(a,b
 /**/) {

    return a+b;

 }

 revivedObj.a(1,2)
3

Ответ 10

Это то, что я сделал https://gist.github.com/Lepozepo/3275d686bc56e4fb5d11d27ef330a8ed

function stringifyWithFunctions(object) {
  return JSON.stringify(object, (key, val) => {
    if (typeof val === 'function') {
      return `(${val})`; // make it a string, surround it by parenthesis to ensure we can revive it as an anonymous function
    }
    return val;
  });
};

function parseWithFunctions(obj) {
  return JSON.parse(obj, (k, v) => {
    if (typeof v === 'string' && v.indexOf('function') >= 0) {
      return eval(v);
    }
    return v;
  });
};