【趣味Javascript】前端开发中不为人知的LHS和RHS查询,你真的弄明白了吗? 《1024程序员节特别篇》

news2025/2/25 15:11:33

🚀 个人主页 极客小俊
✍🏻 作者简介:web开发者、设计师、技术分享博主
🐋 希望大家多多支持一下, 我们一起进步!😄
🏅 如果文章对你有帮助的话,欢迎评论 💬点赞👍🏻 收藏 📂加关注

前言

今天是1024先祝大家节日快乐,那么今天我就给大家讲一个js小知识,也就是LHS和RHS

可能还有很多朋友不知道LHS和RHS是个啥玩意!

那么在我们讲解LHS和RHS之前我们先来回忆一下最简单的赋值操作!

var test=100;
console.log(test);

以上代码的意思简单我们理解为把右边赋值给左边test变量,然后输出打印结果出来对吧,这是最简单的 没什么可说的!

可是我们要是深入理解你就会发现在这个过程当中,还发生了一些其他的事情

而这些事情就是今天我们要说的LHS和RHS

JS到底是解释语言还是编译语言? 题外话

这里我又不得不简单的提两句JS这个解释性语言的一个特性!

在我的印象当中,JS一直是一个解释性语言,简单点说就是执行一行编译解释输出一行,也可以说是边执行边翻译

但根据我查到的一些文档和资料,有人把JS定义为了编译性语言! 为什么呢?

因为JS编译发生在代码执行前的几微秒甚至更短的时间内,让人无法察觉!

就比如之前那段代码:

var test=100;

JS会将其看成两句声明:var testtest=100 弄成两个部分: 编译代码执行

var test 这个部分也就是定义声明的时候就开始进行编译

test=100 而后面这一段赋值声明会留在原地等待代码执行

那么JS中的变量赋值操作会被拆分执行为两个动作:

  1. JS编译器会在当前作用域中声明这个变量,当然是这个变量不存在的情况下!
  2. 然后在运行代码时,JS引擎会在作用域查找这个变量,如果能找到就会对它进行一些操作,例如:赋值操作

而以上这两部的操作又间接引出LHS和RHS的概念!

所以这里的JS编译又与传统的编译语言是不同的!

在这里插入图片描述

LHS与RHS基本概念

LHS 全称为: Left-hand Side(左侧引用)

LHS其实就是赋值操作左侧查询,LHS查询试图找到变量的容器本身,从而对其赋值!

注意: =操作符调用函数时传入参数的操作都会导致赋值操作!

小结

通常情况下,如果查找的目的是对变量进行赋值,那么就会使用LHS查询 也就是当变量出现在赋值操作左侧

RHS 全称为: Right-hand Side(右侧引用)

RHS其实就是赋值操作右侧查询,可以理解为需要获取到某值

小结

通常情况下,如果查找的目的是获取变量或函数的值,就会使用RHS查询, 也就是当变量出现在赋值操作右侧

总的来说LHS和RHS通常是指等号赋值运算的时候,左右边的引用!

可能这样说对于理解LHS和RHS还是比较抽象,我们要用一个案例来解释一下!

举个梨子

console.log(test);

按照LHS与RHS的查找规范, 这段代码就是一个所谓的RHS右侧引用

因为这里test变量,我们并没有对其进行赋值操作,而只是想在作用域当中查找这个变量并取得值,然后输出打印,所以执行的就是RHS

test = 100;

而这段代码当中 按照LHS与RHS的查找规范, 就是一个LHS左侧引用

因为此时JS并不关心当前的值是什么, 只是想要给当前这个赋值操作找到一个目标容器!

我们再看一个案例, 大家可以猜猜看以下代码当中有多少个LHS查询 又有多少RHS查询?

代码如下

function foo(num) {
    console.log(num);
}

foo(100);

分析

  1. 首先function foo(num)这里就存在一个LHS查询 因为100赋值给了num形参对吧,也就相当于num=100,那么就会在这个函数作用域当中先找出num这个变量容器!
  2. foo(100) 本身就是在求返回值的操作, 在作用域当中就会进行RHS查找这个foo(100)函数是否存在, 并没有对其进行赋值操作, 所以这里很明显就是一个RHS查找
  3. 最后console.log(num)这里其实又是一个RHS查询, 因为在这行代码中,我们只有一个变量 num 被使用,因此在 console.log(num) 中只有一个RHS查询,在作用域中查找, 用于获取num的值!

所以正确答案是以上代码当中存在1个LHS查询, 2个RHS查询

所以通过上面的案例最后我们可以把LHS与RHS简单的理解为以下概念:

赋值操作的目标是谁,那么就是LHS(左侧引用查找), 谁是赋值操作的源头,则就是RHS(右侧引用查找)

面试题: 请找出以下代码当中,所有的LHS和所有的RHS

function test(num) {
    var num2 = num;
    return num + num2;
}
var num = test(100);

代码分析

包含LHS的代码

  1. var num = test(100) 这一段代码很显然是一个LHS,因为num在赋值运算的左边,也就是赋值操作的目标,所以要对num变量进行LHS查询, 那么这里的查询过程就是由作用域(词法作用域)进行配合查找的!
  2. function test(num)的形参num在调用test(100)时,将实参100赋值给了形参num,也就是num=100,因为形参num在赋值运算的左边,也就是赋值操作的目标,所以要对形参num进行LHS查询
  3. var num2 = num 这一段代码也是一个LHS,因为num2在赋值运算的左边,也就是赋值操作的目标,所以要对num2进行LHS查询

包含RHS的代码

  1. var num = test(100)这段代码虽然有LHS查询但同时也有RHS 原因之前其实我们也说过,可以把这段代码分成两个部分来看,其中就有test(100)调用这部分,而这里恰恰是要求得一个结果,需要知道test(100)的值是多少 那么根据谁是赋值操作的源头是谁则就是RHS,从而获取test(100)的返回值

  2. var num2 = num也跟上面同理虽然有LHS查询但同时也有RHS,也就是其中也有num这个变量在赋值运算符右边, 此时需要知道num的值 那么根据谁是赋值操作的源头是谁则就是RHS

  3. return num + num2 这里我们按照(词法作用域查找)思维来说需要知道 numnum2的值, 也就是说只是想查找这两个变量,并取得它们的值,然后才是进行求和操作, 所以这里就是RHS查找, 也就是需要分别对num 和num2都进行RHS查询

    那么根据上面的案例当中,要看出左侧右侧并不一定意味这就是=号的左侧和右侧,赋值操作还有其他几种形式

小结

如果查找的目的是对变量进行赋值,那么就会使用LHS查询
如果目的是获取变量的值,就会使用RHS查询
LHS与RHS查找规则

从之前的案例当中,不管是LHS还是RHS 都会在当前执行的作用域中开始查找变量

LHS在查找的时候,是把右边赋值给左边变量那么就会对左边变量进行当前作用域中的LHS查询,来判断是否声明过!

RHS在查找的时候,是先看谁是赋值操作的源头, 然后在这个基础之上进行当前作用域中的RHS查询,简单点说也就是在当前作用域中查找右边变量或者函数表达式来判断是否已经声明过!

那么LHS和RHS在当前作用域当中如果没有找到所需的标识符 就会根据作用域链向上一级作用域继续查找该标识符,以此类推这样每次上升一层作用域去查找, 最后到达全局作用域就会停止,这也是我们之前讲过的作用域链!

我们可以回顾一下之前的作用域链

如图

在这里插入图片描述

LHSRHS都会在当前执行代码的所在环境进行查找, 如果没有找到,才往上一层查找 以此类推, 一旦抵达顶层全局作用域之后,可能找到了你所需的变量,也可能没找到,但无论如何查找过程都将停止!

结合(作用域+编译器+JS引擎)来理解LHS和RHS

我们用一段代码来说明:

var test = 100;

分析

JS引擎 会认为这里有两个完全不同的声明

一个由编译器在编译时处理也就是var test

另一个则由JS引擎在运行时处理,也就是test = 100

编译器遇到var test 会向当前作用域询问是否已经存在这个变量, 如果有就交给编译器继续进行编译赋值, 否则它会要求作用域当前作用域的中声明一个新的变量test

然后JS引擎运行代码的时候,会首先询问作用域,在当前的作用域中是否存在一个叫作test变量, 如果有,JS引擎就会使用这个变量, 如果没有JS引擎会继续根据作用域链查找该变量

如果JS引擎最终找到了test变量,就会将100赋值给它, 否则JS引擎就会抛出一个异常!

LHS与RHS异常问题

RHS查询当前作用域中如果找不到变量,引擎会抛出ReferenceError错误

例如: 直接在整个作用域当中打印输出一个没有定义声明变量或函数就会报ReferenceError错误

如图

我们在举个梨子:

代码如下

function foo(num) {
    console.log(num + data); 
    data = num;
}
foo( 100);

以上的代码当中进行了RHS但无法查找到, 因为作用域是往上查找的,这里也很明显是找不到的!

如图

函数也是一样, 在调用一个完全没有声明函数时也会抛出ReferenceError错误

就比如说如下代码:

test();

如图

所以在作用域中直接调用一个没有定义的test()函数 直接在整个作用域进行了RHS查找也没有查到

自然会报ReferenceError错误

但是如果RHS作用域中查找到变量,但是进行了不规范的操作, 比如: 在末尾加了个()简单点说就是试图对一个非函数类型值/变量进行函数调用 那么JS引擎会抛出另一种异常叫做 TypeError(类型异常)

如图

在这里插入图片描述

还有就是如果RHS作用域中查找到变量, 但是引用了nullundefined 类型的值中的属性,也会报一个TypeError(类型异常)的错误!

知识点复习

在 JS 中,null 和 undefined 是特殊的值,用于表示变量或属性不存在或没有值。
如果你引用 null 或 undefined 类型的值中的属性,意味着你尝试访问一个不存在的属性或者一个没有被赋值的变量。

具体而言,如果你尝试在一个 null 或 undefined 类型的值中访问一个属性,JS引擎会抛出一个类型错误(TypeError),提示你不能在 null 或 undefined 上访问属性。

例如,以下代码会抛出TypeError(类型异常)!

var obj=null;
obj.username;

如图

在这里插入图片描述

所以这里总结以下:

ReferenceError作用域查找失败,也就是说找不到这个变量或者函数才抛出来的

TypeError则代表作用域查找成功了, 但是对结果的操作是非法不合理的!

JS引擎执行LHS查询时,如果在所有作用域中找不到目标变量,就会在全局作用域中创建一个与该变量名相同的全局变量,并将其返回给JS引擎,前提是在非严格模式下 这也正好呼应了我们前面所讲解的隐式全局变量的真正含义!

代码分析
以下函数当中的a = 100其实是一个LHS,但是变量a并没有在函数块当中进行声明就直接赋值了,
那么没声明的变量正常情况下,作用域中是找不到的
那么LHS则会在"全局作用域"中创建一个与该"变量"名相同的"全局变量a"

如图

我们再看一段代码

function foo(a){
  num = a;  //num = 100
}
foo(100);

分析

上面的代码执行的LHS查询,在非严格模式下,JS引擎直到在全局作用域中都没有找到num这个变量,所以它就在全局作用域中声明了一个变量num 当然也对变量a进行一次RHS查询以获得变量a的值, 所以此时结果不会报错, 并且num也被赋值为100

我们也可以使用Chrome调试工具当中的Sources断点来查看全局作用域当中是否真的存在这个num变量,果不其然,我们在global中找到了这个num变量

如图

但是如果是严格模式下会ReferenceError的错误

代码如下:

"use strict";
function test(){
    a=100;
}
test();
console.log(a);

如图

在这里插入图片描述

也就是说在严格模式下,LHS查询是无法帮助我们建立隐式全局变量

LHS与RHS的区别

其实我们在熟悉了LHS和RHS抛出的异常问题之后,就会明白它们彼此的区别在什么地方了!

RHS查询在所有嵌套作用域中找不到所需的变量或函数,引擎就会抛出ReferenceError异常

但是要注意的是,如果RHS查询找到了一个变量,但是对这个变量的值进行不合理的操作, 例如: 使用null或者undefnied类型的属性,这种违规操作, JS引擎会抛出TypeError异常

LHS查询 相比之下,非严格模式的情况下 执行LHS查询时,如果在顶层作用域也无法找到目标变量,那么全局作用域会创建一个具有该名称的隐式全局变量,并将其返回给JS引擎, 当然如果是在严格模式下,LHS查询找不到目标变量时, 依旧会抛出ReferenceError异常

总结

所以区分LHS和RHS很重要的依据就是最终 查询在作用域链中找不到需要的变量函数 会抛出什么!

LHS和RHS都会在当前执行作用域中开始查询,当前没找到,就会根据作用域链上级作用域继续查找目标标识符

不成功的RHS会导致抛出ReferenceError异常

不成功的LHS自动隐式全局作用域中创建一个同名的全局变量 严格模式下也会抛出ReferenceError异常

作用域与LHS和RHS之间的关系

之前我们学过作用域JS引擎用来管理如何在当前作用域以及嵌套的子作用域中根据标识符名称进行变量查找的一套规则

如果查找的目的是对变量进行赋值,那么就会使用LHS查询

如果目的是获取变量的值,就会使用RHS查询

小提示:

要注意一点: 如果代码中引用了类似于foo.bar.baz,那么词法作用域查找只会试图查找foo标识符,找到这个变量后,再根据对象属性访问规则会分别接管, 并对barbaz属性的访问!

"👍点赞" "✍️评论" "收藏❤️"

大家的支持就是我坚持下去的动力!

如果以上内容有任何错误或者不准确的地方,🤗🤗🤗欢迎在下面 👇👇👇 留个言指出、或者你有更好的想法,
欢迎一起交流学习❤️❤️💛💛💚💚

更多 好玩 好用 好看的干货教程可以 点击下方关注❤️ 微信公众号❤️
说不定有意料之外的收获哦..🤗嘿嘿嘿、嘻嘻嘻🤗!
🌽🍓🍎🍍🍉🍇

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1128308.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

你知道AI数字人可以用在哪些行业吗?

引言: 随着科技的不断进步,人工智能(AI)已经渗透到各个领域,其中包括宣传营销。AI数字人是宣传营销领域的一项革命性技术,它们为企业提供了全新的机会,从客户互动到市场分析,再到销…

jenkins实践篇(1)——基于分支的自动发布

问题背景 想起初来公司时,我们还是在发布机上直接执行发布脚本来运行和部署服务,并且正式环境和测试环境的脚本都在一起,直接手动操作脚本时存在比较大的风险就是将环境部署错误,并且当时脚本部署逻辑还没有检测机制,…

初学编程入门基础教学视频,初学编程学什么语言

学习编程捷径:(不论是正在学习编程的大学生,还是IT人士或者是编程爱好者,在学习编程的过程中用正确的学习方法可以达到事半功倍的效果。对于初学者,可以通过下面的方法学习编程,通过对成百上千个实例练习&a…

ilr normalize isometric log-ratio transformation

visium_heart/st_snRNAseq/05_colocalization/create_niches_ct.R at 5b30c7e497e06688a8448afd8d069d2fa70ebcd2 saezlab/visium_heart (github.com) 更多内容,关注微信:生信小博士 The ILR (Isometric Log-Ratio) transformation is used in the anal…

Spring Boot集成RESTful API

在Spring Boot中集成一个RESTful API是我们在实际开发中较为常见的一种开发任务,以下通过一个小的案例来展示在Spring Boot中创建RESTful API来编写一个单元测试。 本节使用到的注解: Controller:修饰class,用来创建处理http请求的…

让锅碗瓢盆变成我们生活的快乐插曲

🌟现代生活中,厨房不再只是一个独立的烹饪区域,而是成为了家庭生活的核心。开放式厨房的设计概念已经成为越来越多家庭的选择,它不仅为我们带来了便利和舒适,还创造了一种与家人和朋友共享美食的愉悦体验。让我们一起探…

线程池常见面试题总结

线程池的工作原理和实现已经在之前的文章中介绍 本文主要总结面试中线程池常问题目。 1、有几种常见的线程池(必知必会)? 1)定长线程池(FixedThreadPool) 2)定时线程池(ScheduledThreadPoo…

25.2 MySQL 运算符

1. 伪表 在MySQL中, DUAL是一个特殊的单行, 单列的虚拟表, 主要用于在SELECT语句中计算表达式或执行函数, 而不需要从实际的数据表中检索数据. 使用DUAL的原因主要有以下几点:* 1. 简化计算: 通过在SELECT语句中使用DUAL, 可以方便地计算表达式或执行函数, 而无需创建临时表或…

android点击全屏预览照片第三方库使用

android点击全屏预览照片第三方库使用-imgepreviewlibrary 移动端我们经常会遇到放大预览照片,如果是一张照片,那就全屏展示图片就好了,但是如果是一个列表,滑动查看,我们一般会借助viewpager进行实现,但是…

【鸿蒙软件开发】ArkTS通用事件

文章目录 前言一、点击事件1.1 基础介绍1.2 ClickEvent对象说明1.3 示例代码 二、触摸事件2.1 基础介绍2.2 ClickEvent对象说明2.3 示例代码 二、焦点事件2.2 基础介绍3.2 示例代码 总结 前言 在我们的ArkTS中有一些通用的事件,他们在所有的组件中都可以用&#xf…

号外!百度Comate代码助手全新上线SaaS服务 - 免费申请试用+深入教程解读!

🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…

全国高清影像数据导出TIF有多大?

全国数据导出为TIF文件之后有多大呢? 我们今天来分析探讨一下这个问题。 01背景 最近,有用户提出在交付数据时,需要交付TIF格式的数据,但我们的地图是基于自研的DAT格式分块存储。 我们在《毫不费力,让内网多一个…

外汇天眼:假冒违法平台害人害己,监管“铁拳”打击!

近年来,金融市场上的假冒违法平台问题日益严重,给投资者和监管机构带来了巨大的挑战。对此,英国FCA、意大利CONSOB和塞浦路斯CySEC等监管机构纷纷出手,打击假冒违法平台,以保护投资者的权益,整肃整个外汇市…

利用Windows自有工具,校验md5值

使用winr&#xff0c;打开cmd命令行窗口 去到对应目录中 对指定目录下的iso进行校验 具体命令行命令为&#xff1a; certutil -hashfile <文件名> <hash类型> md5 SHA1 SHA256都是可以校验的&#xff0c;但我工作中经常校验md5值&#xff0c;就先用了。 很久不写…

中国人民大学与加拿大女王大学金融硕士:培养具有国际视野和专业素养的金融精英

在全球化的今天&#xff0c;金融行业的发展日新月异&#xff0c;对于专业人才的需求也日益增长。为了满足这一需求&#xff0c;中国人民大学与加拿大女王大学联手打造了一款全新的金融硕士项目&#xff0c;旨在培养具有国际视野和专业素养的金融精英。 2013年8月&#xff0c;由…

Spring高手之路15——掌握Spring事件监听器的内部逻辑与实现

文章目录 1. 事件的层次传播2. PayloadApplicationEvent的使用3. 为什么选择自定义事件&#xff1f;4. 事件广播原理4.1 Spring 5.x的事件模型概述4.2 发布事件publishEvent源码分析4.3 Spring事件广播&#xff1a;从ApplicationEventMulticaster开始4.4 Spring事件发布与处理流…

代码随想录 Day27 贪心02上 LeetCode T122 买卖股票的最佳时机 II

LeetCode T122 买卖股票的最佳时机II 题目链接:122. 买卖股票的最佳时机 II - 力扣&#xff08;LeetCode&#xff09; 题目思路: 这题的基本思路还是使用贪心算法,有人可能还在思考啥是贪心算法,这个算法就是你提出一个思想,且找不到明显的反例,这个思路就可以一试,这道题的局…

腾讯云2023年双11云服务器优惠价格表

腾讯云2023年双11大促优惠活动已经拉开序幕&#xff0c;腾讯云推出了一系列云服务器的优惠活动&#xff0c;下面给大家整理分享腾讯云双11云服务器优惠价格表&#xff0c;让大家轻松了解各种云服务器实例的折扣价格和配置信息。 一、腾讯云双十一活动入口 活动入口&#xff1a;…

分类预测 | MATLAB实现SSA-CNN-GRU麻雀算法优化卷积门控循环单元数据分类预测

分类预测 | MATLAB实现SSA-CNN-GRU麻雀算法优化卷积门控循环单元数据分类预测 目录 分类预测 | MATLAB实现SSA-CNN-GRU麻雀算法优化卷积门控循环单元数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.MATLAB实现SSA-CNN-GRU麻雀算法优化卷积门控循环单元数据…

墨西哥专线:国产商品迅速开拓墨西哥市场的基础

随着全球贸易的不断发展&#xff0c;越来越多的中国企业开始将目光投向海外市场。墨西哥作为北美洲的重要国家&#xff0c;拥有庞大的消费市场和广阔的发展空间&#xff0c;对于中国企业来说&#xff0c;无疑是一个极具潜力的市场。然而&#xff0c;如何让国产商品在这个市场上…