深入理解 JavaScript 中的 LHS 与 RHS 查询机制
本文解析 JavaScript 引擎在编译阶段对变量的两种查找方式:LHS(左值)与 RHS(右值)。LHS 查询用于变量赋值,RHS 用于获取变量值。通过代码示例说明两者在函数调用、参数传递及作用域链查找中的区别,以及非严格模式下未找到变量的不同处理结果。
JavaScript 编译三步骤
JavaScript 源代码在执行前需经历编译阶段,该过程包含三个关键步骤。
- 第一步为分词或词法分析。
- 第二步为解析或语法分析。
- 第三步为代码生成。
LHS 与 RHS 查询定义
参考《你不知道的JavaScript(上卷)》第7页的说明,变量赋值操作包含两个动作:编译器首先在当前作用域中声明变量(若未声明),随后运行时引擎在作用域中查找该变量以完成赋值。
LHS 和 RHS 即指上述过程中对变量的两种查找操作,该过程由作用域(词法作用域)协助,在编译的解析阶段执行。
关于 LHS 和 RHS 的概念。
- 其字面含义分别为
Left Hand Side(Left Hand Side)和Right Hand Side(Right Hand Side),即左侧与右侧。 - 一般可以理解为
赋值操作的左侧和右侧
LHS 与 RHS 代码示例解析
首先观察示例一。
console.log(a);
此处对变量 a 进行的是 RHS 引用,因为目的是获取 a 的值并打印,而非赋予新值。
a = 2;
此处对变量 a 进行的是 LHS 引用,因为关注点在于将 a 赋值为 2,而不关心其原有值。
接着观察示例二。
function foo(a) {
console.log(a); // 2
}
foo(2);
- 最后一行 foo(..) 函数调用需要对 foo 进行 RHS 引用,即获取 foo 的值并执行,因此 foo 应为函数类型。
- 此处存在一个易被忽略的隐式赋值操作 a = 2,发生在数值 2 作为实参传入 foo 函数时,即将实参 2 赋值给形参 a,这需要一个 LHS 查询。
- console 行包含对 a 的一次 RHS 引用,同时 console.log(..) 本身也需要对 console 对象进行 RHS 查询,以检查其是否包含 log 方法。
- 书中有一段关于引擎与作用域的对话,有助于深入理解示例二,详见 YDKJS GitHub 仓库。
LHS 与 RHS 查询测验
小测验环节。
function foo(a) {
var b = a;
return a + b;
}
var c = foo(2);
请尝试找出其中的 3 处 LHS 查询和 4 处 RHS 查询。
答案如下。
LHS 查询:
c = ..; a = 2(隐式变量分配);b = ..
RHS 查询
foo(2..) = a; a .. .. b
核心概念总结
小结部分。
参考原书中文版第12页,英文版可查阅 GitHub。
- 作用域是一套规则,用于确定在何处以及如何查找变量(标识符)。
- 若查找目的是对变量进行赋值,则使用 LHS 查询;若目的是获取变量值,则使用 RHS 查询。
- 赋值操作会导致 LHS 查询。= 操作符或调用函数时传入参数的操作都会导致关联作用域的赋值操作,即引发 LHS 查询。
- JavaScript 引擎在代码执行前进行编译,此时像 var a = 2 这样的声明会被分解为两个独立步骤。
- 首先,var a 在其作用域中声明新变量,这发生在代码执行前的初始阶段。
- 接下来,a = 2 会查询(LHS 查询)变量 a 并对其进行赋值。
- LHS 和 RHS 查询均从当前执行作用域开始,若未找到所需标识符,则向上级作用域继续查找,直至全局作用域,无论是否找到均停止。
- 失败的 RHS 引用会抛出 ReferenceError 异常;失败的 LHS 引用在非严格模式下会自动创建全局变量(以 LHS 引用的目标为标识符),在严格模式下则抛出 ReferenceError 异常。
以上为本文全部内容,希望对学习有所帮助,欢迎支持本站。
JavaScript怎么准确判断数据类型:typeof、instanceof与Object.prototype.toString
2026-11-05 17:09:21
JS中将数组和对象混合组装为JSON字符串
2026-11-05 16:41:42
JS运算符优先级与结合性的区别是什么?
2026-11-05 13:22:02
JS Map怎么只遍历Key或Value
2026-11-05 13:00:36
D3.js 与 ECharts 选型对比:灵活性 vs 开发效率
2026-11-05 09:45:01
