为什么你的 JS 代码有时崩溃有时侥幸运行?LHS/RHS 的“潜规则”全解析

JavaScript中的LHS与RHS查询:为什么有的代码会报错,有的却不会?

在 JavaScript 中,变量的查找机制分为 LHS(Left-Hand Side)查询RHS(Right-Hand Side)查询。这两种查询方式在作用域中的行为不同,直接影响了代码是否会抛出错误。本文将通过两个示例代码,详细解释它们的区别。


示例1:RHS查找失败导致报错

javascript 复制代码
function foo(a) {
  console.log(a + b); // RHS查找b失败,报错!
  b = a;
}
foo(2); // 报错:ReferenceError: b is not defined

在这段代码中,函数 foo 试图在 console.log(a + b) 中计算 a + b 的值。此时,引擎会对变量 b 进行 RHS查询 (即查找 b 的值)。然而,在 foo 的作用域内,b 尚未被定义,且全局作用域中也没有 b 的声明。此时 RHS 查找失败,引擎直接抛出 ReferenceError 异常,代码终止执行。

关键点

  • RHS 查询的目的是获取变量的值,失败时会抛出错误。
  • 代码中 b = a 位于 console.log 之后,因此还未执行到这一步,b 未被赋值。

示例2:LHS隐式创建全局变量

javascript 复制代码
function foo() {
  b = 2; // LHS查找b失败,自动创建全局变量!
}
foo();
console.log(b); // 输出2(全局变量生效)

在这段代码中,函数 foo 内部对 b 进行了赋值操作 b = 2。引擎此时会进行 LHS查询 ,尝试找到变量 b 的位置以便赋值。由于当前作用域(foo 内部)和上层作用域(全局)中均未声明 b,在非严格模式下,引擎会隐式地在全局作用域中创建一个全局变量 b 并赋值为 2。因此后续的 console.log(b) 可以正常输出。

关键点

  • LHS 查询的目的是找到变量容器本身(赋值的目标位置),失败时在非严格模式下会隐式创建全局变量。
  • 严格模式("use strict")下,LHS 失败也会抛出 ReferenceError

LHS 与 RHS 的核心区别

  1. 目的不同

    • RHS :查找变量的值(如 console.log(a) 中的 a)。
    • LHS :查找变量容器本身(如 a = 3 中的 a),以便赋值。
  2. 失败时的行为

    • RHS 失败 :直接抛出 ReferenceError
    • LHS 失败(非严格模式):自动在全局作用域创建变量。
    • LHS 失败 (严格模式):同样抛出 ReferenceError
  3. 作用域链的查找机制

    • 两种查询都会沿着作用域链逐级向上查找,直到全局作用域。
    • RHS 失败时立即终止;LHS 失败时(非严格模式)在全局作用域"兜底"。

严格模式下的差异

在严格模式("use strict")中,LHS 的行为会发生变化:

javascript 复制代码
"use strict";
function foo() {
  b = 2; // LHS失败,严格模式下报错!
}
foo(); // ReferenceError: b is not defined

严格模式禁止自动创建全局变量,因此 LHS 查找失败时也会抛出错误,与 RHS 行为一致。


总结

  • RHS 失败必报错:因为引擎需要获取变量的值,找不到时无法继续执行。
  • LHS 失败可能隐式创建变量(仅在非严格模式):这一特性可能导致意外的全局变量污染,需谨慎使用。
  • 推荐使用严格模式:避免隐式全局变量,提升代码安全性。

理解 LHS 和 RHS 的机制,能帮助我们更好地调试作用域相关的问题,并写出更健壮的代码。

相关推荐
JieE2127 小时前
LeetCode 101. 对称二叉树|JS 递归 + 迭代双解法,彻底搞懂镜像判断
javascript·算法
冬奇Lab9 小时前
AI Workflow 定义的四次演进:从 Markdown 到 JS 脚本,再到分布式多 Agent
javascript·人工智能·agent
一颗烂土豆15 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
kyriewen17 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
weedsfly20 小时前
迭代器、生成器与异步迭代——让数据“按需流动”的艺术
前端·javascript
假如让我当三天老蒯20 小时前
前端跨域解决方案(学习用)
前端·javascript·面试
铁皮饭盒1 天前
Bun 哪比 Node.js 快?
javascript·后端
JieE2121 天前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
candyTong1 天前
RTK 技术原理:一次典型会话里,80% 上下文是怎么省下来的
javascript·后端·架构
_柳青杨2 天前
深入理解 JavaScript 事件循环
前端·javascript