如何在JavaScript中序列化函数?
例如,假设我有一个定义如下的函数:如何在JavaScript中序列化函数?,javascript,html,serialization,local-storage,Javascript,Html,Serialization,Local Storage,例如,假设我有一个定义如下的函数: function foo() { return "Hello, serialized world!"; } 我希望能够序列化该函数并使用localStorage存储它。我该怎么做呢?大多数浏览器(Chrome、Safari、Firefox,可能还有其他浏览器)都会从.toString()方法返回函数定义: > function foo() { return 42; } > foo.toString() "function foo() { re
function foo() {
return "Hello, serialized world!";
}
我希望能够序列化该函数并使用localStorage
存储它。我该怎么做呢?大多数浏览器(Chrome、Safari、Firefox,可能还有其他浏览器)都会从.toString()方法返回函数定义:
> function foo() { return 42; }
> foo.toString()
"function foo() { return 42; }"
只是要小心,因为本机函数不会正确序列化。例如:
> alert.toString()
"function alert() { [native code] }"
函数foo(){
警报(“本机函数”);
返回“你好,连载世界!”;
}
连载
var-storedFunction=foo.toString();
反序列化
var actualFunction=new函数('return'+foo.toString())()
解释
toString()将是函数foo的字符串版本
"function foo() { ... return 'Hello, serialised world!';}"
但是新函数
采用函数体,而不是函数本身
看
所以我们可以创建一个函数,返回这个函数,并将它赋给某个变量
"return function foo() { ... return 'Hello, serialised world!';}"
现在,当我们将这个字符串传递给构造函数时,我们得到一个函数,并立即执行它以返回原始函数。:)
这与w(3)不同,w(3)仍然记得添加3。我做这个回答是为了解决现有答案中的一些相当大的缺陷:.toString()
/eval()
和新函数()
如果你的函数使用或命名参数(函数(命名,arg){}
),它们本身根本不起作用,分别
使用下面的,您需要做的就是像往常一样调用函数,然后使用函数
以下内容不适用于简明函数(hello=>'there'
),但对于标准ES5 fat函数,它将按定义返回它,当然,闭包除外
Function.prototype.toJSON=Function(){
var parts=this
.toString()
.match(/^\s*函数[^(]*\([^)]*)\)\s*{(.*)\s*$/)
;
if(parts==null)
抛出“不支持函数形式”;
返回[
“window.Function”,
零件[1].trim().split(/\s*,\s*/),
第[2]部
];
};
Function.deserialise=函数(键、数据){
返回(数组的数据实例和数据[0]=“window.Function”)?
新建(Function.bind.apply(Function[Function].concat(数据[1],[data[2]]):
数据
;
};
看一看
最简单的是:
var test=function(where){return'hello'+where;};
test=JSON.parse(JSON.stringify(test),Function.deserialise);
console.log(test('there'));
//打印“你好”
更有用的是,您可以序列化包含函数的整个对象,并将它们拉回来:
测试={
答:2,,
运行:函数(x,y,z){返回这个.a+x+y+z;}
};
var serialised=JSON.stringify(测试);
控制台日志(序列化);
控制台日志(序列化的类型);
var tester=JSON.parse(序列化、函数反序列化);
console.log(tester.run(3,4,5));
产出:
{“a”:2,“run”:[“window.Function”,[“x”,“y”,“z”],“returnthis.a+x+y+z;”
一串
14
我没有测试旧版IE,但它可以在IE11、FF、Chrome和Edge上运行
注意,函数的属性丢失,如果您使用该属性,那么您真的无能为力。
您可以轻松地将其更改为不使用原型,但如果您需要的话,您可以这样做。如果您需要一种在ES6中串行化的方法,我已经编写了一个串行化器,它可以使一切正常工作
您只需像往常一样对包含函数的函数或对象调用JSON.stringify()
,然后调用function.deserialise
on,魔术就开始了
显然,您不应该期望闭包工作,它毕竟是串行化的,但默认值、解构、此
、参数
、类
成员函数都将被保留。
如果您只使用ES5符号,请使用。这真的是一个超越
在Chrome/Firefox/Edge中工作。
Bellow是演示的输出;一些函数,序列化字符串,然后调用反序列化后创建的新函数
测试={
//制作函数
run:function name(x,y,z){返回这个.a+x+y+z;},
a:2
};
//序列化它,看看它是什么样子
test=JSON.stringify(test)/{“run”:[“window.Function”,[“x”,“y”,“z”],“returnthis.a+x+y+z;”],“a”:2}
test=JSON.parse(test,Function.deserialise)
//看看这个是否有效,应该是2+3+4+5:14
test.run(3,4,5)//14
测试=()=>7
test=JSON.stringify(test)/[“window.Function”、[“”]、“return 7”]
JSON.parse(test,Function.deserialise)(//7
测试=材料=>material.length
test=JSON.stringify(test)/[“window.Function”、[“material”]、“return material.length”]
JSON.parse(test,Function.deserialise)([1,2,3])//3
测试=([a,b]=[1,2],{x:c}={x:a+b})=>a+b+c
test=JSON.stringify(test)/[“window.Function”、[“[a,b]=[1,2]”、“{x:c}={x:a+b}”]、“return a+b+c”]
JSON.parse(test,Function.deserialise)([3,4])//14
班鲍勃{
构造函数(bob){this.bob=bob;}
//没有'function'关键字的fat函数!!
test(){返回this.bob;}
toJSON(){return{bob:this.bob,test:this.test}
}
测试=新鲍勃(7);
test.test()//7.
test=JSON.stringify(test)//{“bob”:7,“test”:[“window.Function”,[“”],“returnthis.bob;”]}
test=JSON.parse(test,Function.deserialise);
test.test()//7.
最后是魔法
Function.deserialise=函数(键,数据){
返回(数组的数据实例和数据[0]=“window.Function”)?
新建(Function.bind.apply(Function[Function].concat(数据[1],[data[2]]):
数据
;
};
Function.prototype.toJSON=Function(){
变量空白=/\s/;
变量对=/\(\)\[\]\{\}/;
var args=新数组();
瓦尔斯特林
w = (function(x){
return function(y){
return x+y;
};
});""+w returns "function(x){
return function(y){
return x+y;
};
}" but ""+w(3) returns "function(y){
return x+y;
}"