eval() 对作用域的影响取决于其调用位置:在全局上下文中直接调用时,它会修改当前作用域内的变量声明;而在函数内部通过非直接方式(如赋值给变量后调用)执行时,它仅能读取当前闭包中的变量,无法修改外层作用域的绑定。

全局上下文中的 eval 如何影响变量声明
当 eval() 作为全局代码的一部分被直接调用时,它在当前作用域内创建的变量和函数会真正注入到该作用域中。这意味着在严格模式下,虽然语法上允许,但行为依然遵循全局环境的规则,即新定义的标识符会被添加到当前的词法环境中。
function testGlobal() {
// 在非严格模式下,eval 可以直接修改局部变量
var x = 10;
eval('var x = 20;');
console.log(x); // 输出 20
}
testGlobal();
// 在全局直接调用
eval('var globalVar = "set";');
console.log(globalVar); // 输出 "set"
上述代码展示了两种情况。首先,在函数内部,如果 eval 是直接调用的,它有权修改局部变量 x。其次,在全局作用域中,eval 创建的 globalVar 成为了全局对象的一个属性(或在模块环境中成为顶层绑定)。这种行为使得 eval 在全局上下文中具有极强的副作用能力,能够动态地改变程序的运行环境状态。
间接调用 eval 时的作用域限制
如果将 eval 赋值给一个变量,或者通过属性访问的方式调用,JavaScript 引擎会将其视为“间接调用”。在这种情况下,eval 始终在全局作用域中执行,并且它创建的任何变量都只会成为全局变量,而无法访问或修改调用者的局部作用域。
function testIndirect() {
var y = 10;
var myEval = eval;
myEval('var y = 20;');
console.log(y); // 输出 10,因为间接 eval 无法修改局部变量 y
console.log(window.y); // 输出 20,y 变成了全局变量
}
testIndirect();
在这个例子中,myEval 是对 eval 的引用。当调用 myEval 时,由于它是间接调用,内部的 var y = 20; 不会修改函数内的局部变量 y,而是创建了一个新的全局变量 y。这证明了间接调用切断了 eval 与当前词法环境的联系,使其退化为纯粹的全局执行环境。
严格模式下 eval 的作用域隔离
在严格模式(strict mode)下,eval() 的行为变得更加受限和安全。当 eval 在严格模式的代码中被直接调用时,它在当前作用域中创建的变量和函数只会存在于一个临时的、匿名的词法环境中,而不会污染外部的实际作用域。
function testStrict() {
"use strict";
eval('var z = 30;');
console.log(typeof z); // 输出 "undefined"
}
testStrict();
// 在全局严格模式下
(function() {
"use strict";
eval('var globalZ = 40;');
console.log(typeof globalZ); // 输出 "undefined"
})();
console.log(typeof globalZ); // 输出 "undefined",未污染全局
这段代码清晰地展示了严格模式下的隔离机制。即使在函数内部直接调用 eval,其声明的 z 也不会出现在函数的词法环境中。同样,在全局严格模式中,eval 也不会向全局对象添加属性。这种设计防止了动态代码执行带来的意外副作用,是推荐的安全实践。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











