LHS与RHS查询

本文基于《你不知道的Javascript》编写。

JavaScript中在预编译后执行代码时对变量的查询分为LHS(Left-Hand-Side)查询和RHS(Right-Hand-Side)查询。
是一个赋值操作的左侧和右侧的意思;

(一)看一个转换后的例子:

function foo(a) {
	console.log( a ); // 2
}
foo( 2 );

代码执行原理图解:
图解

(二)我的分析

示例:

  1. 找到其中所有的 LHS 查询。
  2. 找到其中所有的 RHS 查询。
function foo(a) {
	var b = a;
	return a + b;
}
var c = foo( 2 );

分析:

 (1)var c = foo( 2 );入手.
 c的赋值操作需要对c进行一次LHS查询,foo(2)需要进行一次RHS查询,去获取 foo(2) 的值.
 (2)进入函数声明,foo(a){},这里有一个隐式赋值操作,
 需要对a进行一次LHS查询,判断作用域中是否存在名为a的变量,若存在则直接赋值a=2;
 若不存在,如果是严格模式下,则报ReferenceError:a is not defined.
 		如果非严格模式,则创建一个a的全局变量,并直接赋值a=2;
 (3)var b = a;需要对b进行一次LHS查询,以及对a进行一次RHS查询以获得a的值;
 (4)return a + b;需要分别对a和b进行RHS查询;

(三)为什么区分 LHS 和 RHS 是一件重要的事情?

因为在变量还没有声明(在任何作用域中都无法找到该变量)的情况下,这两种查询的行为是不一样的。
考虑如下代码:

function foo(a) {
	console.log( a + b );
	b = a;
}foo( 2 );

第一次对 b 进行 RHS 查询时是无法找到该变量的。也就是说,这是一个“未声明”的变量,因为在任何相关的作用域中都无法找到它。
如果 RHS 查询在所有嵌套的作用域中遍寻不到所需的变量,引擎就会抛出 ReferenceError异常。值得注意的是,ReferenceError 是非常重要的异常类型。
相较之下,当引擎执行 LHS 查询时,如果在顶层(全局作用域)中也无法找到目标变量,全局作用域中就会创建一个具有该名称的变量,并将其返还给引擎,前提是程序运行在非“严格模式”下。
“不,这个变量之前并不存在,但是我很热心地帮你创建了一个。”
ES5 中引入了“严格模式”。同正常模式,或者说宽松 / 懒惰模式相比,严格模式在行为上有很多不同。其中一个不同的行为是严格模式禁止自动或隐式地创建全局变量。因此,在严格模式中 LHS 查询失败时,并不会创建并返回一个全局变量,引擎会抛出同 RHS 查询失败时类似的 ReferenceError 异常。
接下来,如果 RHS 查询找到了一个变量,但是你尝试对这个变量的值进行不合理的操作,比如试图对一个非函数类型的值进行函数调用,或着引用 null 或 undefined 类型的值中的属性,那么引擎会抛出另外一种类型的异常,叫作 TypeError。
ReferenceError 同作用域判别失败相关,而 TypeError 则代表作用域判别成功了,但是结果的操作是非法或不合理的。

(四)小结

  • 作用域是一套规则,用于确定在何处以及如何查找变量(标识符)。

  • 如果查找的目的是对变量进行赋值,就会使用 LHS 查询;如果目的是获取变量的值,就会用 RHS 查询。

  • 赋值操作会导致 LHS 查询。 = 操作符或调用函数时传入参数的操作都会导致关联作用域的赋值操作, 即都会导致 LHS 查询。

  • JavaScript 引擎首先会在代码执行前对其进行编译,在这个过程中,像var a = 2 这样的声明会被分解成两个独立的步骤:
    1.首先,var a在其作用域中声明新变量。这会在最开始的阶段,也就是代码执行前进行。
    2.接下来,a = 2会查询(LHS查询)变量 a 并对其进行赋值。

  • LHS 和 RHS
    查询都会在当前执行作用域中开始,如果有需要(也就是说它们没有找到所需的标识符),就会向上级作用域继续查找目标标识符,这样每次上升一级作用域,最后到达全局作用域,无论找到或没找到都将停止。

  • 不成功的 RHS 引用会导致抛出 ReferenceError 异常。不成功的 LHS引用会导致自动隐式地创建一个全局变量(非严格模式下),该变量使用 LHS 引用的目标作为标识符,或者抛出ReferenceError异常(严格模式下)。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
C是指一个变量或对象的左值(LHS)和右值(RHS)。引用中提到,只要LHS / RHS值对ostream友好,则将对其进行打印。这意味着如果C是一个类型,它可以被正确地打印到输出流中。引用中提到,当C作为左值时,将调用拷贝构造函数;当C作为右值时,将调用移动构造函数。这说明C可以作为左值或右值进行操作。引用中提到,在C++11中,类与五个特殊函数密切相关,它们是析构函数、拷贝构造函数、移动构造函数、拷贝赋值运算符和移动赋值运算符。这意味着C可以具有这些特殊函数来管理其生命周期和赋值操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [assume:假设是一个更聪明的断言替换(C ++ 03)](https://download.csdn.net/download/weixin_42127835/18470127)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [1.5 C++细节五大函数:析构函数,拷贝构造,移动构造,拷贝赋值,移动赋值](https://blog.csdn.net/wyzeya/article/details/121293393)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Funnee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值