使用 eval() 的奇怪闭包行为——为什么?

Strange closure behaviors using eval() -- why?

首先,请不要警告我不要使用 eval()。我得到它。假设我只是好奇...

接下来,在下面的代码中,eval(...) 创建一个闭包并捕获参数 "arg1"。

var fnStr = "(function() { console.log('closure print arg1: '+arg1);})();";
function test(arg1) {

    eval(fnStr);
}

test('hek');

这个输出是"closure print arg1: hek"。伟大的!不出所料。

但是...如果我将 eval 分配给一个变量并执行相同的操作,则闭包不会捕获 "arg1"。

var fn_ = eval;
var fnStr = "(function() { console.log('closure print arg1: '+arg1);})();";
function test(arg1) {

    fn_(fnStr);
}
test('hek'); 

此代码段的输出是 arg1 未定义。如果我测试以确保 eval 和 fn_ 相等,则它们是 ...

请注意,如果我将 this.arg2 放入 test() 的主体中,则 eval 和 fn_ 都会在闭包中捕获 arg2。所以这种怪异现象似乎只适用于您要关闭的函数的参数。

  1. 为什么会这样?
  2. 如何让它发挥作用?也就是说,我如何将 eval 函数分配给一个变量并使用该变量来捕获参数?

eval是编译器特意识别的。这就是允许它引入和访问局部变量绑定的原因。但是编译器只有在使用它的正常名称时才能识别它。当它看到对 fn_ 的调用时,它无法判断此变量等同于 eval,因此将其编译为普通函数调用。

有关此的更多详细信息,请参阅

javascript eval considered crazy