快速理解JavaScript 中的 LHS 和 RHS 查询

简述编译原理

  • JavaScript 程序中的一段源代码在执行以前会经历三个步骤,统称为 编译
  1. 分词/词法分析
  2. 解析/语法分析
  3. 代码生成
  • 先看原书对一个赋值操做的拆解说明:

变量的赋值操做会执行两个动做,首先编译器会在当前做用域中声明一个变量(若是以前没有声明过),而后在运行时引擎会在做用域中查找该变量,若是可以找到就会对它赋值。 --- 《你不知道的JavaScript(上卷)》 P7html

  • 而要讲的 LHSRHS 就是上面说的对变量的两种查找操做,查找的过程是由做用域(词法做用域)进行协助,在编译的第二步中执行。

LHS 和 RHS

  • 字面意思实际上是 Left Hand SideRight Hand Side 即左手边和右手边
  • 通常能够理解为 赋值操做的左侧和右侧

先看个例子一

console.log(a);
  • 这里对 a 是一个 RHS 引用,由于 a 并无赋予任何值,目的是为了取到 a 的值并打印出来。
a = 2;
  • 这里对 a 是一个 LHS 引用,由于实际上咱们不关心当前的值是什么,只是想要把 a 赋值为 2。

再看例子二

function foo(a) {
    console.log(a); // 2
}
foo(2);
  • 最后一行foo(..)函数的调用须要对 foo 进行 RHS 引用,意味着是取到 foo 的值,而且 (..)意味着 foo 须要被执行,所以它最好是一个函数类型的值
  • 其中有一个容易被忽略的隐式赋值操做 a = 2,它发生在 2 被当作实参传入 foo 中时。即实参 2 传给了形参 a,须要一个 LHS 查询
  • console 那一行还有对 a 的一次 RHS 引用(或者叫查询),同时console.log(..)自己也须要一个 RHS 引用,即对 console 对象进行 RHS 查询,而且检查获得的值中是否有一个叫作 log 的方法。
  • 书中有一段引擎和做用域的对话,有助于很好的理解例子二,see YDKJS github

小测验

function foo(a) {
    var b = a;
    return a + b;
}
var c = foo(2);
  • 试试找出其中的3处 LHS 查询,4处 RHS 查询

<!--more-->git

答案github

  1. LHS 查询:
  • c = ..;
  • a = 2(隐式变量分配)
  • b = ..
  1. RHS 查询
  • foo(2..
  • = a;
  • a ..
  • .. b

小结

参考原书中文版P12,英文版见 githubide

  • 做用域是一套规则,用于肯定在何处以及如何查找变量(标识符)。
  • 若是查找的目的是对变量进行赋值,就会使用 LHS 查询;若是目的是获取变量的值,就会用 RHS 查询。
  • 赋值操做会致使 LHS 查询。 = 操做符或调用函数时传入参数的操做都会致使关联做用域的赋值操做, 即都会致使 LHS 查询。
  • JavaScript 引擎首先会在代码执行前对其进行编译,在这个过程当中,像var a = 2 这样的声明会被分解成两个独立的步骤:函数

    1. 首先,var a在其做用域中声明新变量。这会在最开始的阶段,也就是代码执行前进行。
    2. 接下来,a = 2会查询(LHS查询)变量 a 并对其进行赋值。
  • LHS 和 RHS 查询都会在当前执行做用域中开始,若是有须要(也就是说它们没有找到所需的标识符),就会向上级做用域继续查找目标标识符,这样每次上升一级做用域,最后到达全局做用域,不管找到或没找到都将中止。
  • 不成功的 RHS 引用会致使抛出 ReferenceError 异常。不成功的 LHS 引用会致使自动隐式地建立一个全局变量(非严格模式下),该变量使用 LHS 引用的目标做为标识符,或者抛出 ReferenceError 异常(严格模式下)。

参考

相关文章
相关标签/搜索