LHS和RHS的含义是“赋值操作的左侧或右侧”并不一定意味着就是“=赋值操作符的左侧 或右侧”。赋值操作还有其他几种形式,因此在概念上最好将其理解为“赋值操作的目标是谁 (LHS)”以及“谁是赋值操作的源头(RHS)”。——《你不知道的JavaScript》1
2
3
4function foo(a) {
console.log(a);
}
foo(2); //2
对书中的例子进行简单的分析,foo(a)是一个方法,当被调用后,控制台将会输出a的值。foo(2)调用该方法,其中将2赋值给了参数a,这里就用到了LHS查询;foo(2)调用了foo(a)这个方法,这样可以获得控制台输出值,这里用到了RHS查询[一般认为当能被调用成功,即为RHS,如果不存在被调用的方法,控制台将会报错!]。进入foo(a)这个方法体里面,发现console.log(a)需要在控制台输出a的值,这样就要利用RHS查询,找到谁是赋值操作的源头,也就是值为2。注意[自己也忽略这一点]:console.log( )调用的方法log,console也对其做了RHS查询,并且检查得到的值中是否有一个叫做log的方法。1
2
3
4
5
6
7
8
9
10
11
12
13
14引擎:我说作用域,我需要为foo进行RHS引用。你见过它吗?
作用域:别说,我还真见过,编译器那小子刚刚声明了它。它是一个函数,给你。
引擎:哥们太够意思了!好吧,我来执行一下foo。
引擎:作用域,还有个事儿。我需要为a进行LHS引用,这个你见过吗?
作用域:这个也见过,编译器最近把它声名为foo的一个形式参数了,拿去吧。
引擎:大恩不言谢,你总是这么棒。现在我要把2赋值给a。
引擎:哥们,不好意思又来打扰你。我要为console进行RHS引用,你见过它吗?
作用域:咱俩谁跟谁啊,再说我就是干这个的。这个我也有,console是个内置对象。给你。
引擎:么么哒。我得看看这里面是不是有log(..)。太好了,找到了,是一个函数。
引擎:哥们,能帮我再找一下对a的RHS引用吗?虽然我记得它,但想再确认一次。
作用域:放心吧,这个变量没有变动过,拿走,不谢。
引擎:真棒。我来把a的值,也就是2,传递进log(..)。
……
——《你不知道的JavaScript》
书中有一个小测验,自己也理解了一下:1
2
3
4
5
6function foo(a) {
var b = a;
return a + b;
}
var c = foo( 2 );
//1. 找到其中所有的LHS查询。(这里有3处!) 2.找到其中所有的RHS查询。(这里有4处!)
例子存在一个方法foo(a),用来返回a+b的值,其中参数a的值由调用方法中赋予的值决定,b的值由a值赋予。语句var c = foo(2)中,foo(2)利用RHS查询找到是否存在foo(a)方法,那确实是存在的,其中将2的值赋值给了a,这里用到LHS查询。进入方法体内,语句var b = a中,想要得到b的值,需要先得到a的值,这时利用RHS查询,得到a的值为2,在通过LHS查询,将2赋值给了b;语句return a+b中,要找到a、b中谁是赋值操作的源头,即利用RHS查询,发现2是赋值操作的源头,这里就用了两次RHS查询。跳出方法体后,将返回的值赋值给c,这里用到LHS查询,至此,所有查询都已完毕。书中给出的答案:1
2
3
4//1. 找出所有的LHS查询(这里有3处!)
c = ..;、a = 2(隐式变量分配)、b = ..
//2. 找出所有的RHS查询(这里有4处!)
foo(2..、= a;、a ..、.. b
LHS和RHS查询都会在当前执行作用域中开始,如果有需要(也就是说它们没有找到所需的标识符),就会向上级作用域继续查找目标标识符,这样每次上升一级作用域(一层楼),最后抵达全局 作用域(顶层),无论找到或没找到都将停止。 不成功的RHS引用会导致抛出ReferenceError异常。不成功的LHS引用会导致自动隐式地创建一个全局变量(非严格模式下),该变量使用LHS引用的目标作为标识符,或者抛出ReferenceError异常 (严格模式下)。——《你不知道的JavaScript》