编译原理

程序中的源代码在执行之前会经历三个步骤:

1、分词/词法分析;

2、解析/语法分析(此步骤包含AST);

3、代码生成;

LHS 和 RHS

Example:

1
var a = 2

编译器会做如下处理:

  • 1、var a编译器会询问作用域是否已经存在该名称的变量,如果存在,编译器会忽略该声明,否则在当前作用域中声明一个新的变量,命名为a

  • 2、a = 2赋值操作,会询问当前作用域是否存在a变量,如果存在使用当前变量进行赋值操作。

我们的例子中,引擎会为变量a进行LHS查询,另一个查找类型叫做RHS

LHSRHS的含义是‘赋值操作的左侧或右侧’,并不意味着就是 = 赋值操作符的左侧或右侧,赋值操作还有其他几种形式。概念上最好理解为“赋值操作的目标是谁(LHS)” 以及 “谁是赋值操作的源头(RHS)”。

为什么区分LHS和RHS很重要

考虑以下代码:

1
2
3
4
5
6
function foo (a) {
console.log(a);
b =a;
}

foo(a);

第一次对b进行RHS查询时是无法找到该变量的,这是一个“未声明”的变量。如果RHS在所嵌套的作用域中找不到该变量,就会抛出ReferenceError 异常,

当引擎进行LHS查询时,如果在嵌套的作用域中直至全局作用域中也无法找到目标变量,如果不是严格模式下,就会在全局作用域中创建一个该名称的变量。

LHS和RHS 顺序影响理解 变量提示作用域This


Reference: You Don’t Know JS: Scope & Closures