JavaScript理论
编译器理论
传统的编译器一般包括下面的三种基础步骤:
(1)分词、词法分析;
(2)解析;
(3)代码生成。
我们以 var a = 2;
来举例,
(1)首先,编译器将这一句代码分为几个块儿,可能是var
、 a
、 =
、 2
和;
;具体是否将一个词(比如var、空格等)进行切割,是通过词法分析来判断的;
(2)然后编译器需要将代码解析为一棵抽象语法树;
var
|-----------|
a =
|
2
(3)最后编译器将抽象语法树翻译为计算机可以读懂的代码,引擎运行该代码执行程序。
这三个步骤是最基础的,在编译时还会存在优化执行效率等步骤的存在。JavaScript相对于其他语言的编译器更特殊的是,他不存在预编译的过程,JavaScript代码在运行时,先通过几微妙或者更少的时间进行编译,随后代码就立马执行了。
JavaScript的编译器、引擎和作用域之间的关系
想深入了解JavaScript,我们就需要了解JavaScript里面的三个机制 —— 引擎、编译器和作用域;他们三个协同工作从而能使我们的代码正常的运行。首先我们简单了解一下他们的分工:
(1)引擎:负责从始至终的编译和执行我们的JavaScript程序;
(2)编译器:负责解析和生成可执行的JavaScript代码;
(3)作用域:负责管理所有已声明的标识符列表,对当前代码如何访问变量约束了严格的规则。
同样是这段代码var a = 2;
,我们使用这三个机制分析:
(1)我们首先可以知道的是JavaScript引擎会看到两段代码,一段是编译器在编译期间处理的,另一段是在执行期处理的代码。
(2)接着说一下编译器在此期间的操作:
(2.1)编译器拿到程序会首先根据词法分析进行分词【分词阶段】,然后再将这些拆分的token生成相应的树【解析阶段】;
(2.2)当编译器遇到var a
时,编译器会让作用域在特定的集合中查看是否存在变量a的声明,如果有的话就略过,没有的话就声明a;然后在生成执行期的代码。【代码生成阶段】
(3)最后就是引擎拿着编译器生成的代码开始往后执行a = 2;
,引擎会先让作用域在查找当前作用域是否存在a这个变量,如果有的话就继续赋值操作,如果没有的话就到外层查找,最终在全局作用域中也找不到的话就抛出一个错误。
另外的【LHS & RHS】:
当引擎在执行编译器产生的可执行代码时,还有一个很重要的知识点 —— LHS(left-hand-side) 和 RHS(right-hand-side) 查询,简单来讲(举例)
var a = 2;
①
console.log(a);
②
① 中,对变量a进行赋值操作,则属于LHS引用;
② 中,需要获取变量a的值,属于RHS引用。
我们以下面的代码进一步解释:
function foo(a) {
var b = a;
return a + b;
}
var c = foo( 2 );
下面是引擎、编译器和作用域工作的分析:
(1)编译器进行分析、解析;
(2)在生成代码阶段 ,编译器让作用域创建了全局变量c,function foo,在function foo的作用域内创建了局部变量b和a;
(3)在执行代码阶段,引擎让作用域查看是否存在变量c,foo,并执行了方法foo,最后将foo的返回值赋值给变量c。
下面是关于LHS和RHS的分析:
(1)var c = ...
是对c的赋值操作,属于LHS引用(1L);赋值的右边是foo(...)
,需要RHS引用,找到foo(1R);
(2)在foo(2)
执行时,有一个隐含的LHS引用,将2赋值给参数a(2L);
(3)var b = ...
属于LHS引用(3L);对于赋值操作右边的a
,需要获取a的值,用的是RHS引用(2R);
(4)return a + b
这里需要查询a(3R)和b(4R)的值,用了两次RHS查询;
总结
-
作用域是一组规则,他规定了一个变量(标识符)在哪里和如何被查找。这种查询也许是为了向这个变量赋值,这时变量是一个LHS引用;也许是为了获取这个变量的值,这时变量是一个RHS引用;
-
LHS引用是自赋值操作,可以通过
=
赋值,也可以通过函数参数传递赋值; -
LHS和RHS引用查询都是从当前作用域开始,逐步向外层查找,直到在全局作用域中停止,未被满足的RHS查找会抛出一个ReferenceError引用错误;在非严格模式下,未被满足的LHS查找,会在全局作用域中创建一个变量,在严格模式下不可以在全局中创建变量,同样会抛出ReferenceError的引用错误;
-
当RHS查询的值被错误的操作,会抛出TypeError的类型错误。
-
JavaScript引擎在代码运行之前进行编译,因此,他将
var a = 2;
进行分离的操作;(1)代码执行前,在当前作用于声明a(2)代码执行时,进行LHS引用赋值。
网友评论