【javascript】作用域的理解(LHS,RHS查询)

作用域是什么?

一,理解作用域

任何javascript代码片段在执行前都要进行编译,先看一个例子吧:

// 先思考一下这行代码是如何被编译的?
var a = 33

// 估计大部分人看到这行代码,会说首先声明一个变量a,然后给它赋值33
// 但实际上并没有这么简单

首先要先知道js在解析var a = 33这行代码的时候都有哪些东西参与了。

  1. 引擎:从头到尾负责整个js程序的编译及执行过程
  2. 编译器:负责语法分析及代码生成
  3. 作用域:简单点说就是存储变量的仓库,引擎和编译器通过(LHS,RHS)查询,来查找变量是否存在。暂时可以将LHS和RHS理解为一种查询方式,下边会详细说。

基于上文,事实上编译器会这么处理,继续拿var a = 33来举例子:

var a = 33

/** 
* 1. 编译器会去逐行进行语法分析和代码生成,所以它首先会遇到var a
* 2. 编译器去作用域中查询(LHS),变量a是否存在,如果存在,就继续往下编译,
*   否则就会在作用域中新建一个变量a
* 3. 然后编译器会生成a = 33这行代码并交给引擎去执行,这时候引擎会向作用域发起查询(LHS),
* 询问当前作用域中是否存在变量a,如果不存在,就会向当前作用域的上一级作用域去查找
* (可以理解为当前作用域仓库外边套了一个更大的仓库,在当前仓库找不到,就跑到仓库外边那个更大的仓库去找),也叫作用域链。
* 如果在这条作用域链中还是没找到,那么就会在顶级(最最外边那个仓库)作用域下创建一个a变量,并给它赋值33
* 如果在当前作用域找到了,就会直接将33赋值给a
*/ 
二.LHS和RHS查询

上文中多次提到LHS和RHS查询,那么它俩到底是啥呢?

简单点说,当变量出现在赋值操作的左侧时是LHS查询,非左侧时是RHS查询。也可以将LHS理解成是给谁赋值,RHS理解为赋值操作的源头。

// 举个例子吧
console.log(a)
/**
*这里的a就是一个RHS查询,因为a没有发生任何赋值操作,所以肯定不在赋值操作的左侧,那么就是非左侧,所以它是一个RHS查询。
*然后还有一个console,同上,所以它也是一个RHS查询,回去作用域链中查找console这个对象,查到之后就会调用它的log方法去打印出a
*/

然后再深入思考下,如果通过RHS查询,并且在作用域链中没有找到变量a呢?这时候引擎就会抛出一个ReferenceError错误,表示RHS查询失败,那么如果LHS查询失败呢?

大家先来看看俩例子吧,看完这俩例子可能会对作用域以及作用域链和LHS,RHS查询有更深刻的理解:

// 先来看看下边这个例子
function fn(a) {
  b = a;
}
fn(3);
console.log(b);
/**
*毫无疑问,它打印的是3,然后我们来分析一下过程:
*执行fn函数,引擎想要获取fn的结果,所以对这个函数发起了一次RHS查询
*将实参3赋值给形参a,也就是a = 3,这里的a进行了一次LHS查询
*然后b = a,这里对b进行了一次LHS查询,注意!!!然后问题出现了!!!
*引擎对b进行LHS查询的时候,在当前作用域没找到,所以它就会在上级作用域中去找
*但是在上级作用域中同样没找到,这时候它就会在顶级作用域(就是这里的最外围作用域)中去创建一个变量b
*然后对a进行RHS查询,在作用域中找到a的值之后,赋值给b
*最后打印b,对b发起一次RHS查询,因为之前已经创建过并且给b赋值了,所以可以查询到b的值
*最后对console发起RHS查询并顺利打印出3
*/
// 再来看看下边这个例子
function fn(a) {
  console.log(a + b);
}
fn(3);

/**
 *这时候大家肯定会知道这样会报b is not defined的错,但如果分析一下为什么呢?
 *首先先来看看都发生了几次LHS以及RHS查询:
 *执行fn函数,发生了一次RHS查询,会去当前作用域中查找函数fn,然后找到了
 *接着进行了一次隐式操作,给形参a赋值实参3,也就是a = 3,那么这里就对a进行了一次LHS查询
 *接着执行console.log(a + b)
 *因为log方法想获取a + b的值,所以会对a和b分别进行一次RHS查询,对B进行查询的时候在作用域链中没找到,所以会抛出ReferenceError的错误.
 */

总结

  1. 作用域就相当于一个存储变量的仓库,作用域链就相当于仓库外边又套了一层仓库,如果在当前作用域(也就是当前仓库)没有找到变量的话,那么就会在上级作用于(外层仓库)去找,就这样一层层找,直到顶级作用域。
  2. LHS和RHS,可以这样理解:如果查找的目的是对变量进行赋值,那么就是LHS查询。如果是获取变量的值,那么就是RHS查询
a = 3
//这里就是LHS查询,因为是对a赋值了
console.log(a + b)
//这里就是RHS查询,因为log这个方法想要获取a+b的值.
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值