Есть ли возможность иметь функции сохранения JSON.stringify? - PullRequest
22 голосов
/ 13 октября 2011

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

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

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

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

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

Ответы [ 11 ]

8 голосов
/ 24 июля 2013

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

5 голосов
/ 13 октября 2011

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

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

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

4 голосов
/ 13 октября 2011

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

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

https://yuilibrary.com/yui/docs/json/json-freeze-thaw.html

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

3 голосов
/ 24 апреля 2018

В последнее время у меня было похожее требование.Чтобы было ясно, вывод выглядит как JSON, но на самом деле это просто javascript.

JSON.stringify работает хорошо в большинстве случаев, но «не работает» с функциями.

У меня получилось работать с несколькими трюками:

  1. использовать replacer (2-й параметр JSON.stringify())
  2. использовать func.toString(), чтобы получитькод JS для функции
  3. запоминает, какие функции были преобразованы в строку и заменяет их непосредственно в результате

. И вот как это выглядит:

// our source data
const source = {
    "aaa": 123,
    "bbb": function (c) {
        // do something
        return c + 1;
    }
};

// keep a list of serialized functions
const functions = [];

// json replacer - returns a placeholder for functions
const jsonReplacer = function (key, val) {
    if (typeof val === 'function') {
  	    functions.push(val.toString());
        
        return "{func_" + (functions.length - 1) + "}";
    }
        
    return val;
};

// regex replacer - replaces placeholders with functions
const funcReplacer = function (match, id) {
   return functions[id];
};

const result = JSON
    .stringify(source, jsonReplacer)               // generate json with placeholders
    .replace(/"\{func_(\d+)\}"/g, funcReplacer);   // replace placeholders with functions

// show the result
document.body.innerText = result;
body { white-space: pre-wrap; font-family: monospace; }

Внимание: Будьте внимательны с форматом заполнителя - убедитесь, что он не слишком общий.Если вы измените его, также измените регулярное выражение, если применимо.

2 голосов
/ 19 октября 2016

Это то, что я сделал 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;
  });
};
2 голосов
/ 03 ноября 2014

непослушный, но эффективный способ заключается в следующем:

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

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

1 голос
/ 25 ноября 2014

Вполне возможно создавать функции из строки без 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
1 голос
/ 10 марта 2014

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

Я столкнулся с проблемой при написании скрипта для изменения конфигурации RequireJS.Вот как я это сделал.Во-первых, есть немного кода ранее, который гарантирует, что заполнитель, используемый внутри (">>>F<<<"), не отображается как значение в конфигурации RequireJS.Очень маловероятно, но лучше, чем потом сожалеть.Входная конфигурация читается как объект JavaScript, который может содержать массивы, атомарные значения, другие Object s и функции.Это было бы просто stringifiable как 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, которое определяет алгоритм строкового преобразования и не может найти случай, когда возникнет проблема с упорядочением.Если этот алгоритм изменится в будущем издании, исправление будет состоять в том, чтобы использовать уникальные плашдолеры для функций и использовать их для обращения к функциям, которые будут храниться в ассоциативном массиве, отображающем уникальные заполнители в функции.

1 голос
/ 11 сентября 2013

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

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

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

1 голос
/ 13 октября 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...