JavaScript的LHS和RHS查询

1,531 阅读3分钟
var number = 1;

当你看到这段代码的时候,你可能简单的认为是为变量number赋值为1\color{red}{number赋值为1}。事实上,这里是分为两个阶段处理,一个是编译器编译处理,一个是引擎运行处理。是由编译器和引擎协助工作。

  • 首先将分词/词法分析这段代码分解为词法单元。
  • 然后解析语法分析,生成一个抽象语法树-AST。
  • 最后进行代码生成。

引擎:负责整个JavaScript的编译和执行过程。

编译器:负责JavaScript的语法分析和代码生成。

一、编译器生成代码时做了什么?

  1. 遇见var number,编译器会询问作用域中是够已经有一个名称为number的变量存在于当前作用域中,如果存在,会忽略当前声明。如果不存在就是在当前作用域声明一个变量number。这这个阶段是进行变量提升的一个过程【JavaScript变量提升运行机制】。

  2. 然后编译器会生成引擎运行时需要的代码。生成代码用来处理赋值的操作。

  3. 引擎运行时,首先会询问当前作用域是否有一个变量number,如果有直接使用这个变量。如果没有,引擎会继续查询该变量。直至最外层(全局作用域)。如果引擎找到变量number,就将1这个值赋给number,反之引擎会抛出一个异常。

详情完整的JavaScript的代码运行机制,请看这里

引擎执行怎么样的查找,?在我们的例子中,引擎会为变量number进行LHS查询,与之相对的就是RHS查询。\color{red}{引擎执行怎么样的查找,}?\color{red}{在我们的例子中,引擎会为变量number进行LHS查询,与之相对的就是RHS查询。}

二、LHS查询&RHS查询

正常的猜想"L"、"R"就是左边和右边,赋值操作的左边和右边,根据这个猜想,当变量出现在赋值操作的左侧是进行LHS查询,当再出现赋值操作的右边进行RHS查询。

console.log(number);

这段代码对number的引用是一个RHS查询,这里number没有赋值任何值,(可能你会说,兄弟你这一行代码会报错,没有声明变量number,不好意思,打扰了举着栗子。)

number = 1;

这里对number是一个LHS查询,引擎并不关心当前赋值的值是什么,只是想为 = 1 找到一个目标。

LHS查询和RHS查询的含义是"赋值操作的左侧和右侧",并不一定是意味着是" = 赋值操作符的左侧和右侧"。赋值操作还有其他几种形式,因此在概念上最好将其理解为"赋值操作的目标是谁(LHS)"以及"谁是赋值操作的源头(RHS)"。                         
                                          
                                          
                                           ----------摘抄《你不知道JavaScript上卷》
function func(number) {
    console.log(number);
}
func(1);

上面的代码既有LHR查询也有RHS查询,我们一起来分析一下。

  1. 运行func()函数时,对func进行了RHS查询,查询func操作的源头。
  2. 隐藏的声明number = 1,这里是将1传给函数func,1被分配赋值给number,查询操作的目标是谁,进行一次LHS查询。
  3. console.log需要一个查询才能执行,先会对console,进行一个RHS查询,并检查console对象是否有一个log的方法。
  4. 然后会对number进行一个RHS查询。
  5. 最后在console.log()输出number的值。

看似简单的一段代码执行,其中进行了很多的LHR查询和RHS查询,这就是引擎需要重复操作的动作。

三、小测试

function foo(a) {
    var b = a;
    console.log(a);
    console.log(b);
    return a + b; 
}

var c = foo(2);
  1. 找出其中所有LHS查询。
  2. 找出其中所有RHS查询。

参考【《你不知道JavaScript上卷》】