能否设置方法作用域为调用位置?Node.js+TypeScript场景求助
问题与解决方案
问题背景
我有两个文件,代码如下:
file1.js
class helper { static wrap(code) { eval(`console.log("start"); ${code} console.log("stop");`); } }
file2.js
import { helper } from "./file1.js"; // TypeScript + Node.js环境 function somethingCool() { console.log("middle"); } helper.wrap("somethingCool();");
这段代码跑不起来,因为somethingCool是定义在file2里的,wrap方法里的eval用的是file1的作用域,根本找不到这个函数。我想让eval用调用wrap时的作用域(也就是file2的作用域),而不是wrap自己的本地作用域。目前只想到传个匿名函数当锚点:
helper.wrap("somethingCool();", (val) => eval(val));
但这么写太麻烦了,每次调用都得加这个锚点,有没有更简洁的办法?
可行方案
1. 直接传函数(最推荐)
别传字符串代码了,让wrap接收一个函数参数。函数本身就带着自己定义时的作用域,调用的时候自然能访问到somethingCool:
修改file1.js:
class helper { static wrap(callback) { console.log("start"); callback(); console.log("stop"); } }
file2里这么调用:
import { helper } from "./file1.js"; function somethingCool() { console.log("middle"); } // 两种写法都可以 helper.wrap(somethingCool); // 需要传参数的话:helper.wrap(() => somethingCool(xxx));
这种写法不仅解决了作用域问题,还避开了eval的安全风险,代码也更清爽,完全符合JS的最佳实践。
2. 传递作用域对象(折中方案)
如果一定要传字符串代码,可以让调用者把需要用到的变量/函数打包成对象传进去,然后在wrap里把这些变量注入到eval的作用域:
修改file1.js:
class helper { static wrap(code, scope = {}) { // 把传入的作用域变量挂载到当前eval的上下文 for (const [key, val] of Object.entries(scope)) { eval(`var ${key} = scope['${key}'];`); } eval(`console.log("start"); ${code} console.log("stop");`); } }
file2调用:
import { helper } from "./file1.js"; function somethingCool() { console.log("middle"); } helper.wrap("somethingCool();", { somethingCool });
虽然比锚点函数简洁点,但还是得手动传需要的变量,不如直接传函数方便。
3. 依赖调用者上下文(不推荐)
还有一种方式是利用arguments.callee.caller获取调用者的函数,进而拿到调用者的eval,但这种方法在严格模式下(模块默认是严格模式)会直接报错,而且属于废弃特性,容易出问题,完全不建议在生产环境用,这里只做演示:
class helper { static wrap(code) { const callerEval = arguments.callee.caller.eval; callerEval(`console.log("start"); ${code} console.log("stop");`); } }
总结
优先用传函数的方案,既解决问题又安全简洁,别纠结用eval传字符串的写法了,本来eval就不推荐随便用。
内容的提问来源于stack exchange,提问作者Nick Frev
相关产品推荐
相关产品推荐

