在 JavaScript 开发中,LHS 和 RHS 是两个绕不开的概念。
对此,《你不知道的JavaScript》此书中的解释是:
当变量出现在赋值操作的左侧时进行LHS查询,出现在右侧时进行RHS查询。
RHS查询与简单地查找某个变量的值别无二致,而LHS查询则是试图找到变量的容器本身,从而可以对其赋值。
我的理解是:它们就像程序运行时的“找人”过程——一个负责“找谁放值”,一个负责“找谁要值”。
下面,我将通过我的理解,再结合一些案例简单说说。
一、LHS 和 RHS 到底是啥?
1. LHS 查询(Left-Hand Side)
LHS 查询的目标是找到变量的容器,以便进行赋值操作。
换句话说,LHS 查询关注的是“变量存储的位置和变量的初始化”。
典型使用场景:
- 变量赋值:
var a = 10; - 参数传递:
function foo(a) { ... }
2. RHS 查询(Right-Hand Side)
RHS 查询的目标是获取变量的值,以便用于计算或传递。
RHS 查询关注的是“变量值的查询和传递”。
典型使用场景:
- 使用变量:
console.log(a); - 函数调用:
foo();
二、在实际开发应用中的使用
话不多说,先来两个案例,请找出其中的LHS查询和RHS查询。
例1:
function foo(a) {
console.log(a);
}
foo(2);
答案:
LHS 查询有:
foo ( 2 ), 隐式 LHS 查询:相当于var a = 2,对a进行初始化
RHS 查询有:
console.log(a), RHS 查询 a 的值并输出
例2:
function foo(a) {
var b = a; // LHS 查询 b,RHS 查询 a
return a + b; // RHS 查询 a 和 b
}
var c = foo(2); // LHS 查询 c,RHS 查询 foo(2)
答案:
LHS 查询有:
var b = ..., 对b的初始化var c = ..., 对c的初始化... = foo(2), 隐式 LHS 查询:相当于var a = 2,对形参a进行初始化
RHS 查询有:
... = a, 查询a的值并传递(给b)return a + b,查询a的值和b的值并返回。... = foo(2)查询 foo(2)的值并传递(给c)
现在,你或许大致对LHS和RHS的使用有个大致的了解,这时,你再回过头来看这几句话:
-
LHS 查询关注的是“变量存储的位置和变量的初始化”
-
RHS 查询关注的是“变量值的查询和传递”。
-
RHS查询负责查找某个变量的值,而LHS查询则负责找到变量的容器本身,然后把RHS查询到的值赋值进去。
此时,你是否有了不一样的感悟?
小贴士:
在例2中:
var b = a
var c = foo(2)
在这种变量声明和赋值过程中,LHS 和 RHS 会交替出现。
三、一点小小的扩展
1. ## 变量不存在时的行为
| 查询类型 | 非严格模式 | 严格模式 |
|---|---|---|
| LHS | 自动给你创建一个全局变量 | 直接甩锅:ReferenceError |
| RHS | 返回 undefined | 同样甩锅:ReferenceError |
举一个栗子:
// 非严格模式下,LHS 会偷偷给你造个变量
a = 10; // a 会变成全局变量,别慌!
// 严格模式下,LHS 就很刚
function bar() {
'use strict';
a = 10; // 报错:a is not defined(不给你自动创建了!)
}
2. RHS 查询失败的后续影响
ReferenceError:变量未声明时抛出。TypeError:变量已声明但无法进行预期操作时抛出(如调用非函数值或访问null/undefined的属性)。
举两个栗子:
// RHS 查不到变量?直接报错
console.log(b); // ReferenceError: b is not defined
// RHS 找到变量但操作不对劲?
var c;
c(); // TypeError: c is not a function(c 是 undefined,没法调用)
四、踩坑指南:这些错误你遇到过吗?
1. 隐式全局变量污染
非严格模式下,忘记声明变量赋值会自动创建全局变量,容易造成命名冲突。
解决办法:
- 开启严格模式(
'use strict';),让错误显性化。 - 始终用
let/const/var显式声明变量。
2. RHS 查询失败的连锁反应
未声明变量的 RHS 查询可能导致程序崩溃。
解决办法:
- 在访问变量前进行检查(如
typeof a !== 'undefined')。 - 使用默认值(如
||或??运算符)。
五、LHS 和 RHS 对比总结
| 特性 | LHS 查询 | RHS 查询 |
|---|---|---|
| 目标 | 找变量的存储位置(初始化) | 获取变量的值(使用) |
| 失败行为(非严格模式) | 自动创建全局变量 | 返回 undefined |
| 失败行为(严格模式) | 报错:ReferenceError | 报错:ReferenceError |
| 典型场景 | 变量赋值、参数传递 | 变量读取、函数调用 |
| 异常关联 | 隐式赋值失败 → ReferenceError | 变量未声明 → ReferenceError操作非法 → TypeError |
六、总结一下
LHS 和 RHS 其实就是 JavaScript 引擎在“找人办事”时的两种态度:一个是“我要把值放到谁身上”,另一个是“我要从谁身上取值”。
掌握它们的区别,不仅能帮你写出更稳定的代码,还能让你看懂那些“离谱”的报错信息。
以上为小编的个人理解,如有不对的地方,欢迎各位大佬在评论区指正!