We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
文章部分论述截自原书《你不知道的JavaScript(上卷)》。
与其他语言不同,JavaScript的编译过程不是发生在构建之前的。对于JavaScript来说,大部分情况下编译发生在代码执行前的几微秒(甚至更短)的时间内。
举个栗子,var a = 2;JavaScript引擎会将它分为几步完成呢? 答案是两步,JavaScript 会将其看成两句声明:var a;和a = 2;。第一个定义声明在编译阶段进行,第二个赋值声明会被留在原地等待执行阶段。
var a = 2;
var a;
a = 2
下面是原书对这句声明的拆解分析:
变量的赋值操作会执行两个动作,首先编译器会在当前作用域中声明一个变量(如果之前没有声明过),然后在运行时引擎会在引用域中查找该变量,如果能够找到就会对它赋值。
而要讲的LHS和RHS就是上面说的对变量的两种查找操作,查找的过程是由作用域(词法作用域)进行协助,在编译的第二步中执行。
LHS
RHS
LHS(Left-hand Side)引用和RHS(Right-hand Side)引用。通常是指等号(赋值运算)的左右边的引用。 我们来看下面这句代码:
LHS(Left-hand Side)
RHS(Right-hand Side)
console.log(a);
这里对a的引用是一个RHS引用,因为这里a并没有赋予任何值,我们只是想查找并取得a的值,然后将它打印出来。
RHS引用
查找并取得a的值
a = 2;
这里对a的引用是一个LHS引用,因为我们并不关心当前的值是什么,只是想要为赋值操作找到目标。
LHS引用
为赋值操作找到目标
注:LHS和RHS的含义是“赋值操作的左侧和右侧”并不一定意味这就是"="的左侧和右侧。赋值操作还有其他几种形式,因此在概念上最好将其理解为“赋值操作的目标是谁(LHS)”以及“谁是赋值操作的源头(RHS)”。
这里再举一个较复杂的例子:(找出所有的LHS查询和所有的RHS查询)
function foo(a) { var b = a; return a + b; } var c = foo(2);
这里一共有3个LHS查询和4个RHS查询,这里我们都来做个分析。 LHS:
c = ...
foo(2)
b = ...
RHS:
c = foo(2)
b = a
reutrn a + b;
小结:如果查找的目的是对变量进行赋值,那么就会使用LHS查询; 如果目的是获取变量的值,就会使用RHS查询。
LHS查询
RHS查询
因为在变量还没有声明(在任何作用域中都无法找到该变量)情况下,这两种查询行为是不一样的。
LHS和RHS查询都会在当前执行作用域中开始,如果有需要(也就是说他们没有找到所需的标识符),就会向上级作用域继续查找目标标识符,这样每次上升一次作用域,最后抵达全局作用域,无论找到或没找到都将停止。
借用书中的一张图,将作用域链比喻成一个建筑,在对上面的论述进行一次转换。
这个建筑代表储蓄中的嵌套作用域链。第一层楼代表当前的执行作用域,也就是你所在的位置。建筑的顶层代表全局作用域。
LHS 和 RHS 引用都会在当前楼层进行查找,如果没有找到,就会坐电梯前往上一层楼,如果还是没有找到就继续向上,以此类推。一旦抵达顶层(全局作用域),可能找到了你所需的变量,也可能没找到,但无论如何查找过程都将停止。
总结:不成功的RHS引用会导致抛出ReferenceError异常。不成功的LHS引用会导致自动隐式地创建一个全局变量(非严格模式下),该变量使用LHS引用的目标作为标识符,或者抛出ReferenceError 异常(严格模式下)。
ReferenceError异常
ReferenceError 异常
The text was updated successfully, but these errors were encountered:
No branches or pull requests
与其他语言不同,JavaScript的编译过程不是发生在构建之前的。对于JavaScript来说,大部分情况下编译发生在代码执行前的几微秒(甚至更短)的时间内。
举个栗子,
var a = 2;
JavaScript引擎会将它分为几步完成呢?答案是两步,JavaScript 会将其看成两句声明:
var a;
和a = 2
;。第一个定义声明在编译阶段进行,第二个赋值声明会被留在原地等待执行阶段。下面是原书对这句声明的拆解分析:
而要讲的
LHS
和RHS
就是上面说的对变量的两种查找操作,查找的过程是由作用域(词法作用域)进行协助,在编译的第二步中执行。LHS 和 RHS
LHS(Left-hand Side)
引用和RHS(Right-hand Side)
引用。通常是指等号(赋值运算)的左右边的引用。我们来看下面这句代码:
这里对a的引用是一个
RHS引用
,因为这里a并没有赋予任何值,我们只是想查找并取得a的值
,然后将它打印出来。这里对a的引用是一个
LHS引用
,因为我们并不关心当前的值是什么,只是想要为赋值操作找到目标
。这里再举一个较复杂的例子:(找出所有的LHS查询和所有的RHS查询)
这里一共有3个LHS查询和4个RHS查询,这里我们都来做个分析。
LHS:
c = ...
,c 在赋值操作的左边,所以对 c 需要 LHS 查询。a = 2
(隐式变量分配),在调用foo(2)
时,需要将实参2赋值给形参a,所以对 a 需要 LHS 查询。b = ...
, 解释同 1。RHS:
c = foo(2)
,foo(2) 在赋值操作的右边,需要知道 foo(2)的值,对 foo(2) 需要 RHS 查询。b = a
, a 在赋值操作的右边,需要知道 a的值,对 a 需要 RHS 查询。reutrn a + b;
, 需要知道 a 和 b 的值, 分别对 a 和 b 都进行 RHS 查询。区分 LHS 和 RHS 的重要性
因为在变量还没有声明(在任何作用域中都无法找到该变量)情况下,这两种查询行为是不一样的。
LHS
和RHS
查询都会在当前执行作用域中开始,如果有需要(也就是说他们没有找到所需的标识符),就会向上级作用域继续查找目标标识符,这样每次上升一次作用域,最后抵达全局作用域,无论找到或没找到都将停止。借用书中的一张图,将作用域链比喻成一个建筑,在对上面的论述进行一次转换。
这个建筑代表储蓄中的嵌套作用域链。第一层楼代表当前的执行作用域,也就是你所在的位置。建筑的顶层代表全局作用域。
LHS 和 RHS 引用都会在当前楼层进行查找,如果没有找到,就会坐电梯前往上一层楼,如果还是没有找到就继续向上,以此类推。一旦抵达顶层(全局作用域),可能找到了你所需的变量,也可能没找到,但无论如何查找过程都将停止。
总结:不成功的RHS引用会导致抛出
ReferenceError异常
。不成功的LHS引用会导致自动隐式地创建一个全局变量(非严格模式下),该变量使用LHS引用的目标作为标识符,或者抛出ReferenceError 异常
(严格模式下)。The text was updated successfully, but these errors were encountered: