(笔记)JS编译原理

159 阅读2分钟

JavaScript(简称“JS”) 是一种具有函数优先的轻量级,解释型或即时编译型的高级编程语言。 由上面一句话了解到,js是一门解释型语言

编译型语言 vs 解释型语言

  • 编译型语言:代码在运行前将人类可以理解的语言转换成机器能够理解的语言
  • 解释型语言:代码在运行时将人类可以理解的语言转换成机器能够理解的语言

编译过程

js编译过程分为三步:

1.分词和词法分析

把代码拆分为一些对编程语言有意义的代码块(词法单元)
譬如 var a = 1;将拆分为var; a; =; 2;一个个的词法单元,这些一个个的词法单元会组成一个词法单元流进行解析

2.解析和语法分析

将词法单元集合分析并得到一个层级嵌套的语法树,称为抽象语法树(Abstract Syntax Tree,AST)

3.预编译

当js引擎在预编译脚本时,会先对所有的变量个函数进行处理,并且是先预声明变量再预声明函数

4.将上一步的AST转换成可执行代码执行

js中的编译器、引擎、作用域

  • 编译器:主要将人类理解的语言转换成机器可以理解的语言(负责词法分析,语法分析,代码生成)
  • 引擎:负责整个过程中JavaScript的编译及执行过程
  • 作用域:负责收集并维护所有的标识符(变量)

作用域(定义变量的区域)

  • 静态作用域 or 词法作用域(函数的作用域在函数定义的时候就已经决定了)
var a = 1;
function demo() {
	var a = 2;
    console.log(a)
}

function test() {
	var a = 3;
    demo();
}
demo();  // 打印值为2
由于js采用的静态作用域,函数的作用域在定义时就已经决定了,所以执行demo方法时会先从自己的作用域查找有没有a变量,有就打印,没有就继续向上查找
  • 动态作用域

变量提升

有了词法分析的过程,变量提升的原理有很好懂了,因为引擎执行代码的时候编译器已经做了一些处理,找到所有的变量声明和函数声明并用合适的作用域关联起来,这也是词法作用域的核心,但是赋值处理操作因为是在执行阶段,因此编译阶段他们原地待命等待执行,函数表达式不会提前声明。

b = 2;
var b;
console.log(b);  //输出2
console.log(c);  //输出undefined
var c = 2;
var d;
alert(d); //输出undefined
d = 2;

参考文章:

JavaScript 编译原理、编译器、引擎及作用域

JavaScript深入之词法作用域和动态作用域