我有一个 JS 对象,我想保存在本地存储中以备将来使用,但我无法将其解析为字符串。
代码:
JSON.stringify({
a: 5,
b: function (param) {
return param;
}
})
结果:
"{"a":5}"
如果不使用 JSON,我该如何保存以备将来使用?
(并创建我自己的 Lexer-Parser 来中断字符串函数,我认为这不是一个选项)
我有一个 JS 对象,我想保存在本地存储中以备将来使用,但我无法将其解析为字符串。
代码:
JSON.stringify({
a: 5,
b: function (param) {
return param;
}
})
结果:
"{"a":5}"
如果不使用 JSON,我该如何保存以备将来使用?
(并创建我自己的 Lexer-Parser 来中断字符串函数,我认为这不是一个选项)
我推荐这种方法:
将参数和正文存储在您的 json 中:
{"function":{"arguments":"a,b,c","body":"return a*b+c;"}}
现在解析 json 并实例化函数:
var f = new Function(function.arguments, function.body);
我认为这是保存
通常这样的问题表示一个 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 + ")");
)没有这种神奇的能力,它在全局范围内运行。
一种简单的方法是
var dstr = JSON.stringify( { a: 5
, b: x => x
}
, (k,v) => typeof v === "function" ? "" + v : v
);
我已经将函数名和参数值一起存储在一个数组中,数组中的第一项是函数名,前面带有 a $
,以将它们与普通数组分开。
{
"object": {
"your-function": ["$functionName", "param-1", "param-2"],
"color": ["$getColor", "brand", "brand-2"],
"normal-array": ["normal", "array"]
...
}
}
在上面的例子中,我有 Sass 和 JS 函数来从全局地图/对象中检索颜色值。以这种方式解析函数自然需要自定义代码,但在 JSON 中“存储”函数方面,我喜欢这种方式。