Function.prototype.toString() 返回函数定义的原始源代码字符串(如"function add(a, b) { return a + b; }"),对箭头函数、bind函数、内置函数等返回受限格式,且不包含闭包、作用域链或可执行环境,无法用于反序列化或动态注入逻辑。

Function.prototype.toString 不能用于“反序列化函数体逻辑”,它只是返回函数的源代码字符串(格式化后),且该字符串不可靠、不可执行、不包含闭包环境,也不能还原作用域链或私有状态。试图用它动态注入可运行逻辑存在根本性误解和严重安全风险。
它实际返回什么?
调用 fn.toString() 仅返回函数定义的原始文本(可能带换行缩进),例如:
function add(a, b) { return a + b; }
add.toString();
// → "function add(a, b) { return a + b; }"对于箭头函数、绑定函数、类方法或内置函数,结果更受限:
- 箭头函数:返回类似
() => {}的字符串,无函数名 -
fn.bind():返回"function () { [native code] }" - 内置函数(如
JSON.parse):一律返回"[native code]" - 经过压缩/混淆/打包的代码:返回已变形的源码,无法直接复用
为什么不能靠它“动态注入逻辑”?
即使你拿到字符串形式的函数体,要让它真正运行,还需解决以下不可绕过的问题:
-
作用域丢失:闭包中捕获的变量(如外层 const、let)不会出现在字符串里,
eval或Function构造器无法恢复 -
词法环境断裂:模块导入、
this绑定、super、new.target等上下文信息完全丢失 -
执行权限限制:现代浏览器对
eval和Function构造器施加严格 CSP 策略,生产环境通常禁用 -
安全红线:拼接并执行任意字符串 = 开放远程代码执行(RCE)漏洞,等同于
eval(userInput)
真正可行的替代方案
若目标是“运行时加载并执行动态逻辑”,应选择设计安全、可控、可调试的机制:
- 预定义函数模板 + 安全参数注入:服务端返回纯数据(如表达式配置、规则描述),前端在白名单内解析执行(如 math.js、jsonlogic)
-
Web Worker + 沙箱脚本:将动态代码放入独立 Worker 中加载,隔离 DOM 和全局作用域,配合
postMessage通信 -
AST 解析与受控求值:用
acorn等解析表达式为 AST,手动遍历执行(只允许 + - * / 变量访问等安全子集) -
模块动态导入:通过
import('./logic.js')加载预编译、签名验证过的模块,由浏览器原生保障执行环境
一句话总结
toString() 是调试和元编程的观察工具,不是序列化/传输/重建函数的手段;任何试图靠它实现“动态注入”的做法,本质是在绕过 JavaScript 的作用域模型和安全边界,既不可靠,也不可持续。

















