JavaScript中eval与with的机制、风险及严格模式限制详解

作者:函数茶馆

时间:2026-10-30

浏览:618

本文深入解析JavaScript中eval()函数与with语句的执行机制。eval将字符串作为代码执行,影响作用域并导致性能下降;with简化深层对象访问但易引发变量泄漏。在严格模式下,eval创建变量的能力受限,而with被完全禁止。文章通过代码示例说明其副作用及最佳实践建议。

文章目录

eval与with概述

前言

eval和with在JavaScript开发中常受诟病,仿佛它们的存在本身就是一种错误。这类似于CSS领域中,表格若仅用于展示数据而非布局,虽被指责为不规范,但有时也属于矫枉过正。那么,eval和with的真实情况究竟如何?本文将深入剖析eval()函数与with语句的具体行为。

eval函数详解

eval函数

定义

eval()是JavaScript的全局函数,用于解释并执行由JavaScript源代码组成的字符串。


var result = eval('3+2');
console.log(result,typeof result);//5 'number' 

用法

eval()仅接受一个参数。若传入的参数非字符串,则直接返回该参数。若参数为字符串,引擎会尝试将其编译为JavaScript代码:编译失败时抛出SyntaxError异常;编译成功后则执行该代码,并返回字符串中最后一个表达式或语句的值;若最后无返回值,则返回undefined。若字符串执行过程中抛出异常,该异常将向上传递给eval()调用处。


var num = 1;
var str = 'test';
console.log(eval(num));//1
console.log(eval(str));//ReferenceError: test is not defined 
var strLong1 = 'var x = 1;var y = 2;';
console.log(eval(strLong1),x,y);//undefined 1 2
var strLong2 = 'var x = 1; x++;';
console.log(eval(strLong2),x);//1 2 

作用域

eval()在执行时,会复用调用它时的变量作用域环境。这意味着,在eval中查找变量值或定义新变量、函数的行为,与在局部作用域中直接编写代码完全一致。


var b = 2;
function foo(str,a){
eval(str);
console.log(a,b);
}
foo('var b = 3;',1);//1 3 

别名调用

当通过别名(如将eval赋值给其他变量)调用时,eval()会将传入的字符串视为顶层全局代码执行。此时,代码可以定义新的全局变量或全局函数,或修改全局变量,但无法访问或修改调用函数内部的局部变量。


var geval = eval; 
var x = 'global',y = 'global'; 
function f(){
var x = 'local';
eval('x += "changed";');
return x;
}
function g(){
var y = 'local';
geval('y += "changed";');
return y;
}
console.log(f(),x);//localchanged global
console.log(g(),y);//local globalchanged 

[注意]在IE8及更低版本的浏览器中,通过别名调用eval()的结果与直接调用eval()相同,即仍遵循局部作用域规则。

副作用

JavaScript解释器会对代码进行大量分析与优化。然而,eval()动态执行的代码通常无法被静态分析,导致解释器无法对其进行优化,从而引起性能显著下降。

与eval()类似的机制包括setTimeout()、setInterval()以及new Function()构造函数,它们均接受字符串参数并在运行时动态执行。这种动态执行机制带来的便利性往往无法弥补其性能损耗,因此应尽量避免使用。

严格模式

鉴于eval()功能过于强大且潜在风险高,JavaScript严格模式对其施加了严格限制。

【1】在严格模式下,不能通过eval()创建变量或函数,但仍可查询和修改已存在的全局变量值。


'use strict';
eval('var x = 1;');
console.log(x);//ReferenceError: x is not defined
'use strict';
var x = 1;
eval('x = 2;');
console.log(x);//2 

【2】严格模式下禁止将eval作为标识符(变量名或函数名)。


'use strict';
var eval = 10;//SyntaxError: Unexpected eval or arguments in strict mode 

with语句机制

with语句

定义

with语句的主要目的是简化对同一对象多次属性访问的代码编写。


with(object){
  statement;
}

作用

当对象嵌套层级极深时,开发者常借助 with 语句来精简代码逻辑。其核心机制是将对象引用视作作用域,把对象属性映射为作用域内的标识符,进而生成一个全新的词法作用域。

在对象嵌套层级较深时,通常使用with语句来简化代码。其本质是将对象引用作为作用域处理,将对象属性视为作用域中的标识符,从而创建一个新的词法作用域。


document.forms[0].address.value 

在客户端JavaScript开发中,常需通过类似document.forms[0].address.value的表达式访问HTML表单元素。


with(document.forms[0]){
name.value = '';
address.value = '';
emai.value = '';
} 

若此类表达式在代码中频繁出现,可使用with语句将form对象提升至作用域链顶层。这种方法大幅减少了输入代码量,无需为每个属性名重复添加document.forms[0]前缀。该对象临时挂载于作用域链上,当JavaScript解析如address等标识符时,会自动在此对象中查找。

[注意]with语句提供了一种读取对象属性的快捷方式,但它并不能创建对象的属性。

若对象o已拥有属性x,以下代码会将该属性值赋为1。


var o = {x:0};
with(o) x = 1;
console.log(o.x);//1 

若对象o中未定义属性x,以下代码与不使用with语句的x=1行为完全一致。这是因为对变量x进行了LHS(左值)查询,并将1赋值给该变量。


var o = {};
with(o) x = 1;
console.log(o.x);//undefined
console.log(x);//1 

副作用

与eval类似,with语句的代码极难优化,且会增加调试难度。相比不使用with的代码,其运行速度更慢。

此外,若with语句使用不当,可能导致变量泄漏,进而污染全局作用域。


var x = 1;
var o = {};
with(o){
x = 2;
}
console.log(x);//2
console.log(o.x);//undefined 

严格模式

在严格模式下,禁止使用with语句。


//SyntaxError: Strict mode code may not include a with statement
'use strict';
var o = {};
with(o){
x = 2;
}

总结与建议

总结

使用eval和with会阻碍引擎在编译阶段对作用域查找进行优化,导致性能下降及代码运行变慢。由于eval和with在实际工作中极少使用,严格模式下的限制对大多数开发者影响甚微。这好比某国宣布不再发放前往某地的签证,虽该地知名,但多数人此生未必前往,故无需过度担忧。同理,eval和with是否被嫌弃,在实际应用中已无关紧要。

以上所述是小编给大家介绍的JavaScript学习小结之被嫌弃的eval函数和with语句实例详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对本站网站的支持!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章