Как сохранить функцию Javascript в JSON

У меня есть объект JS, который я хотел бы сохранить в локальном хранилище для будущего использования, и я не могу разобрать его в строку.

Код:

JSON.stringify({
    a: 5,
    b: function (param) {
        return param;
    }
})

Результат:

"{"a":5}"

Как сохранить его для будущего использования, если не с JSON?

(И создание собственного Lexer-Parser для прерывания строковой функции, я не думаю, что это вариант)

7 ответов

Решение

Обычно такой вопрос указывает на проблему X/Y: вам нужно сделать X, вы думаете, Y поможет вам в этом, поэтому вы пытаетесь сделать Y, не можете и спрашиваете, как сделать Y. Часто это было бы более полезно спросить, как сделать X вместо этого.

Но отвечая на заданный вопрос: вы можете использовать функции replacer и reviver для преобразования функции в строку (во время stringify) и обратно в функцию (во время parse) для хранения строковой версии функции, но при этом возникают всевозможные проблемы, не в последнюю очередь то, что область, в которой определяется функция, может иметь большое значение для функции. (Это не имеет значения для функции, которую вы показали в вопросе, но я полагаю, что это не совсем репрезентативно.) А преобразование строки из локального хранилища в код, который вы можете запустить, означает, что вы доверяете тому, что содержимое локального хранилища не имеет был поврежден злонамеренно. Конечно, это маловероятно, если страница уже не подвержена атакам XSS, но об этом следует помнить.

Вот пример, но я не рекомендую его, если не исчерпаны другие параметры, не в последнюю очередь потому, что он использует eval, который (как и его близкий родственник new Function)) может быть вектором для вредоносного кода:

// The object
var obj = {
    a: 5,
    b: function (param) {
        return param;
    }
};

// Convert to JSON using a replacer function to output
// the string version of a function with /Function(
// in front and )/ at the end.
var json = JSON.stringify(obj, function(key, value) {
  if (typeof value === "function") {
    return "/Function(" + value.toString() + ")/";
  }
  return value;
});

// Convert to an object using a reviver function that
// recognizes the /Function(...)/ value and converts it
// into a function via -shudder- `eval`.
var obj2 = JSON.parse(json, function(key, value) {
  if (typeof value === "string" &&
      value.startsWith("/Function(") &&
      value.endsWith(")/")) {
    value = value.substring(10, value.length - 2);
    return eval("(" + value + ")");
  }
  return value;
});
document.body.innerHTML = obj2.b(42);

Я бы порекомендовал этот подход:

Сохраните аргументы и тело в вашем JSON:

{"function":{"arguments":"a,b,c","body":"return a*b+c;"}}

Теперь проанализируйте json и создайте экземпляр функции:

var f = new Function(function.arguments, function.body);

Я думаю, что это сохранить

Вы не можете хранить функции в JSON.

Значение в JSON может содержать только строку, число, объект, массив, true, false или же null:

Проверьте это на сайте JSON.

Один простой способ сделать это

var dstr = JSON.stringify({
                           a: 5,
                           b: param => param
                          }, (k,v) => typeof v === "function" ? "" + v : v);

Я создал JSON.parseIt() а также JSON.stringifyIt() функции на основе первого ответа без использования eval

Проблемы, которые я исправил, были

  • Удален eval.
  • возникла проблема с преобразованием в строку и синтаксическим анализом: если я дам строку типа "/ Function(hello) /", то при синтаксическом анализе будет функция
  • Сделано для двух функций

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

{
    "object": {
        "your-function": ["$functionName", "param-1", "param-2"],
        "color": ["$getColor", "brand", "brand-2"],
        "normal-array": ["normal", "array"]
        ...
    }
}

В приведенном выше примере у меня есть функции Sass и JS для получения значений цвета из глобальной карты / объекта. Естественно, такой анализ функции требует специального кода, но с точки зрения "хранения" функций в JSON, мне нравится такой способ.

Для тех, кому по какой-либо причине все еще необходимо включить определение функции в JSON, этот код может помочь (но может быть медленным в зависимости от размера объекта):

      function Object2JsonWithFunctions(o, space = null) {
var functionList = {}
var fnSeq = 0;

var snrepl = function(k,v){
    if(typeof v === 'function'){
        fnSeq++;
        var funcName = `___fun${fnSeq}___`;
        var funcText = ''+v;
        
        functionList[funcName] = funcText
        
        return funcName;
    }
    
    return v;
}

var RawJson = JSON.stringify(o, snrepl, space);

for(func in functionList){
    var PropValue = `"${func}"`;
    RawJson = RawJson.replace(PropValue, functionList[func])
}

return RawJson;}

Код выполнит обычное преобразование в JSON. Для функций исходная строка будет возвращаться как "prop":"function()..." (функция как строка)... Приведенный выше код создаст заполнитель (например: "prop":"fn1") и создаст список функций... После этого каждый заполнитель будет заменен исходным телом функции...

Другие вопросы по тегам