-
编译原理
-
分词/词法分析 tokenizing/lexing
- 将代码字符串分解,如
var a = 2;
会被分解为var、a、=、2、;。每个独立的单元成为词法单元(token). - 空格是否作为词法单元,看空格是否有意义。
- 词法单元生成器判断a是否为其他词法单元的一部分,调用的是有状态的解析规则,这个过程就是词法分析。 如果是无状态,就是分词。
- 将代码字符串分解,如
-
解析/语法分析
- 将此法单元流(数组)转换为抽象语法树。如下图
- 将此法单元流(数组)转换为抽象语法树。如下图
-
代码生成
- 将AST转换为可执行代码的过程。
- 即将写的代码翻译为一组机器指令,创建变量,分配内存,并将值储存其中。
- 将AST转换为可执行代码的过程。
-
对于var a
-
-
理解作用域
- 引擎
- 程序的编译和执行
- 编译器
- 语法分析和代码生成等
- 作用域
- 收集并维护由所有标识符组成的一系列查询,确定当前执行的代码对这些标识符的访问权限
- 变量的赋值
- 编译器在当前作用域中声明一个变量(如果之前没有声明过);运行时引擎在作用域中查找该变量,能找到就对它赋值
- 引擎
-
LHS和RHS
-
变量在赋值操作的左边,进行LHS查询;右边RHS
-
RHS查询就是查找某个变量的值,LHS查询是找到变量的容器,所以可以对其赋值
console.log(a); // RHS
要查找a的值a = 2; //LHS
为 = 2这一赋值操作找一个目标(容器)-
function foo(a) {
console.log( a ); // 2
}foo(2);
1. 最后一行foo(..)的调用,RHS引用, 因为要找到foo的值 2. 传参时,隐式的a = 2操作,LHS查询,= 2的容器查找 3. console.log(a)的RHS查询a的值 4. 若console.log()可以接收参数,将2(上面的RHS查询找到a的值)赋值给arg1,参数1为LHS。
- 函数声明是LHS还是RHS?
-
-
作用域嵌套
- 作用域是用来确定在哪里以及如何查找标识符的规则。
-
why lhs & rhs?
- 对于未声明的变量
- 若为LHS,即为被赋值的容器
- 若为严格模式,ReferenceError
- 若为非严格模式,自动创建一个变量(全局作用域中),返还给引擎。
- 若为RHS,找不到该值,ReferenceError
-
练习
-
凡是右侧的标识符(不是数字,包括函数,标识符和数字的二进制表示不同)。都要进行RHS