JavaScript中函数转字符串后如何恢复为无闭包的原函数
问题原因
你遇到的执行返回undefined的问题,根本不是外层闭包包装导致的,是你对new Function的API使用方式有误:new Function的传入规则是最后一个参数为函数体字符串,前面的所有参数为新函数的形参名。你将完整的函数字符串直接传入作为函数体时,相当于创建了一个如下逻辑的新函数:
function b() { // 你传入的a.toString()结果在这里只作为一段普通的表达式执行,没有被返回 () => { return "hello world" } }
这段逻辑只是在函数体内定义了一个未被调用的箭头函数,没有任何返回值,自然执行b()就输出undefined。
解决方案
方案1:使用eval直接反序列化(可信场景下最便捷)
对于合法的函数表达式字符串,直接用eval包裹即可还原出原函数,注意要给函数字符串外层套一层括号,避免JS引擎将函数表达式解析为函数声明报错:
const a = () => { return "hello world" } const aString = a.toString() const b = eval(`(${aString})`) console.log(b()); // 输出 hello world
方案2:手动拆分参数与函数体,适配new Function
如果你不想用eval,可以先将序列化后的函数字符串拆解为「参数列表」和「函数体」两部分,再传入new Function创建:
const a = (num) => { return "hello world " + num } const aString = a.toString() // 简易拆分逻辑(生产环境建议用更完善的正则匹配兼容所有函数写法) const paramPart = aString.match(/\((.*?)\)/)[1] const params = paramPart ? paramPart.split(',') : [] const bodyPart = aString.match(/\{(.*)\}/s)[1] const b = new Function(...params, bodyPart) console.log(b(123)); // 输出 hello world 123
注意事项
所有JS函数的序列化反序列化方案,都只能还原不依赖外部作用域变量的纯函数:如果原函数引用了外部闭包变量、全局上下文变量,反序列化后的函数运行时会因为找不到对应变量抛出异常,因为函数的执行上下文环境是无法被序列化的。
内容的提问来源于stack exchange,提问作者Jackson
相关产品推荐
相关产品推荐

