JavaScript作用域本质是词法作用域,eval和with会动态修改作用域导致引擎放弃优化、性能下降;严格模式下eval受限但仍慢,with已被ES5禁用;JSON.parse、解构赋值、方括号访问等是更安全高效的替代方案。

JavaScript 的作用域本质是一套变量查找规则,核心是词法作用域——即函数或块级作用域在代码**写好时就已确定**,不依赖运行时调用位置。而 eval 和 with 是仅有的两种能在运行时“动态修改”词法作用域的机制,正因如此,它们会直接破坏引擎的优化能力,导致显著性能下降。
词法作用域依赖静态可分析性
JS 引擎(如 V8)在编译阶段会对代码做大量静态分析:预判变量声明位置、绑定标识符到具体作用域气泡、建立快速查找路径。这种优化要求作用域结构在编译期就完全确定。
- 一旦源码中出现
eval或with,引擎无法静态确认后续代码中变量引用的真实归属 - 例如
eval("var x = 1")可能向当前函数作用域注入新变量,也可能不执行;with(obj)会让a = 2既可能赋值给obj.a,也可能泄漏为全局变量——这些都只能在运行时才知道 - 引擎被迫放弃所有基于作用域的优化(如内联缓存、变量地址预分配、作用域链剪枝),退回到最保守、最慢的动态查找模式
eval 动态注入代码,使作用域不可预测
eval 接收字符串并将其当作当前位置的原始代码执行,相当于在运行时“重写”了局部作用域。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 它可能声明新变量(如
"var b = 3"),遮蔽外层同名变量,改变原有作用域结构 - 即使字符串内容看似固定,引擎也无法在编译期验证其安全性——因为字符串可能来自用户输入、网络请求或拼接逻辑
- 严格模式下
eval被限制在独立作用域中,虽缓解污染,但仍无法恢复编译优化,性能代价依旧存在
with 临时插入对象作用域,打乱查找链
with 将传入对象的属性临时提升为词法标识符,等效于在作用域链顶端插入一个新层级。
立即学习“Java免费学习笔记(深入)”;
- 原本的变量查找只需遍历函数 → 全局两层,
with后变成对象 → 函数 → 全局三层,且对象属性是否含某标识符需运行时判定 - 更严重的是歧义:赋值语句
a = 2在with(obj)中,引擎无法预先判断是设置obj.a还是创建全局a,必须逐层检查并动态决定 - ES5 严格模式已彻底禁用
with,正是因其不可控性和对性能与安全的双重损害
替代方案简单有效,无需妥协
所有合理使用 eval 或 with 的场景,都有更清晰、更高效、更安全的替代方式。
- 解析 JSON:用
JSON.parse(),比eval快且无执行风险 - 批量操作对象属性:解构赋值或临时变量,如
const {a, b, c} = obj; a = 3; b = 4; - 动态属性访问:用方括号语法
obj[key],明确、可控、无作用域副作用 - 需要动态执行逻辑:提前定义函数并按需调用,避免字符串拼接和运行时编译


















