如何为已声明的函数定义其自身作用域内的局部变量
JavaScript 函数的词法作用域在函数定义阶段就已经确定,原生没有提供直接为已声明函数追加局部变量的API,可通过以下两种方案实现你要的效果:
方案1:动态构造新函数(生成真正的局部变量)
核心思路是解析原函数的文本内容,注入局部变量声明后重新生成新函数,该方案生成的新函数内部的t是严格意义上的局部变量:
function defineLocals(fn, locals) { const fnContent = fn.toString(); // 提取原函数参数 const paramsMatch = fnContent.match(/^function\s*\w*\s*\(([^)]*)\)/); const params = paramsMatch ? paramsMatch[1] : ''; // 提取原函数体 const bodyMatch = fnContent.match(/\{([\s\S]*)\}$/); const originalBody = bodyMatch ? bodyMatch[1] : ''; // 拼接局部变量声明 const declareStr = Object.entries(locals).map(([key, val]) => { return `var ${key} = ${JSON.stringify(val)};` }).join(''); // 返回新函数 return new Function(params, declareStr + originalBody); } // 测试用例 function x() { return t; } const y = defineLocals(x, { t: 123 }); console.log(y()); // 输出 123
注意:该方案会丢失原函数持有的外层闭包引用,仅适合不依赖外部作用域变量的纯函数场景。
方案2:with 作用域包装(兼容原函数闭包)
如果需要保留原函数的闭包引用,可以通过with语法注入变量上下文,运行效果和局部变量一致,只是不属于函数x的内部局部声明:
function defineLocals(fn, locals) { return function(...args) { with (locals) { return fn.apply(this, args); } } } // 测试用例 function x() { return t; } const y = defineLocals(x, { t: 456 }); console.log(y()); // 输出 456
注意:with语法在ES5严格模式下被禁用,若你的运行环境开启了严格模式请选择方案1。
内容的提问来源于stack exchange,提问作者JSX
相关产品推荐
相关产品推荐

