如何在 JSON 中存储 javascript 函数

IT技术 javascript json
2021-02-11 14:39:48

我有一个 JS 对象,我想保存在本地存储中以备将来使用,但我无法将其解析为字符串。

代码:

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

结果:

"{"a":5}"

如果不使用 JSON,我该如何保存以备将来使用?

(并创建我自己的 Lexer-Parser 来中断字符串函数,我认为这不是一个选项)

6个回答

我推荐这种方法:

将参数和正文存储在您的 json 中:

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

现在解析 json 并实例化函数:

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

我认为这是保存

它以 json 方式保存,但出于安全原因不保存。new Function 总是在全局范围内创建一个函数。这至少是一个安全风险。
2021-04-05 14:39:48
这帮助我解决了一个几乎不相关的问题。谢谢!
2021-04-06 14:39:48
解构也很适合这个!这也让我省了很多头痛!
2021-04-09 14:39:48

通常这样的问题表示一个 X/Y 问题:你需要做 X,你认为 Y 会帮助你做到这一点,所以你尝试做 Y,不能,并询问如何做 Y。它通常会更多询问如何做 X 很有用。

但是回答提出的问题:您可以使用 replacer 和 reviver 函数将函数转换为字符串 (during stringify) 并返回到函数 (during parse) 以存储函数的字符串版本,但是这样做有各种各样的问题,尤其是定义函数的范围可能对函数很重要。(这与您在问题中显示的函数无关,但我认为这不是真正具有代表性的。)并且将字符串从本地存储转换为您可以运行的代码意味着您相信本地存储内容没有t 被恶意破坏。当然,除非页面已经容易受到 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 (0, eval)("(" + value + ")");
  }
  return value;
});
document.body.innerHTML = obj2.b(42);

该构造(0, eval)("(" + value + ")");确保eval在全局范围内运行,而不是在 reviver 函数的范围内运行。通常eval具有使用您调用它的作用域的魔法能力,但只有在您直接调用它时才有效。如图所示的间接eval(或只是var e = eval; e("(" + value + ")");)没有这种神奇的能力,它在全局范围内运行。

嗯,这取决于网站,我见过显示随机用户内容的网站被利用。这实际上意味着一些用户可能会在该网站上被持续利用,而不是在他们访问该页面时(因为标准网页代码是评估任意 JS 的代码)。我想如果不知道 OP 的应用程序就很难知道。
2021-03-21 14:39:48
有点坏死,但eval您可以将字符串传递给Function(+value.substring()+ ,而不是使用)developer.mozilla.org/en-US/docs/Web/JavaScript/Reference /... 函数构造器确实有一个更有限的范围来防止一些eval攻击
2021-03-22 14:39:48
@user161778:如果该站点已经容易受到 XSS 的攻击,我认为这不会使情况变得更糟。如果不是,由于本地存储与源相关联,我认为这不会打开一扇新的大门。但我同意:我不会这样做。
2021-03-25 14:39:48
非常感谢,此解决方案有效!这个项目并不广泛访问,它仅适用于我的公司,我相信我的项目易受 XSS 攻击,但据我所知,这并没有打开新的大门。如果我将函数存储在数据库中,当然,有人可以向每个人注入代码。
2021-03-27 14:39:48
不见得?呃,如果网站在任何地方容易受到 XSS 攻击,可能比我们想象的更有可能。我当然希望提问者重新考虑他的方法。
2021-03-29 14:39:48

您不能在 JSON 中存储函数。

在JSON的值可能只包含字符串号码对象阵列truefalsenull

在此处输入图片说明

在 JSON 站点上查看它

“没有办法在 JSON 中存储函数。” ——那不是真的。这只是表明没有本机函数数据类型。一个函数可以表示为一个字符串。
2021-03-15 14:39:48
有没有办法将函数转换为字符串并反向转换?
2021-03-17 14:39:48
@denysdovhan - 哦,不是,但“可怕的想法”离“不可能”还有很长的路要走
2021-03-25 14:39:48
这个答案在技术上是正确的 IMO。您不是在存储函数,而是在存储可以评估为函数的字符串。
2021-03-25 14:39:48
@Amit 是的,您可以使用 来执行此操作(function () { ... }).toString(),但这不是好方法。也许您必须多考虑一下您的情况才能在不使用函数的情况下解决该问题。
2021-04-08 14:39:48

一种简单的方法是

var dstr = JSON.stringify( { a: 5
                           , b: x => x
                           }
                         , (k,v) => typeof v === "function" ? "" + v : v
                         );
杰出的!我不知道是否会因某些功能而失败,具体取决于它的内容,但我会改进这一点,这对我来说似乎是最干净的方式
2021-04-02 14:39:48
此外,相反的将是 JSON.parse(json, (k,v) => typeof v === "string"? (v.startsWith('function')? eval("("+v+")") : v): v)
2021-04-09 14:39:48

我已经将函数名和参数值一起存储在一个数组中,数组中的第一项是函数名,前面带有 a $,以将它们与普通数组分开。

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

在上面的例子中,我有 Sass 和 JS 函数来从全局地图/对象中检索颜色值。以这种方式解析函数自然需要自定义代码,但在 JSON 中“存储”函数方面,我喜欢这种方式。