一·编译原理
javascript是一种“解释执行”语言。它跟传统的编译语言编译时间不一样但编译的步骤基本相似且javascript的要更为复杂。因为与其他编译语言不同,他不需要提前进行编译,就导致了他没有太多时间进行优化,他只是在代码执行前进行几毫秒的编译。所以,他就想各种方法来进行性能优化,比如JIT(延迟编译)甚至实施重编译。
二·3个处理代码的重要角色
- 引擎:负责编译和执行全过程的
- 编译器:进行语法分析及代码生成等累活
- 作用域:收集并维护由所有已声明的标识符组成的一系列查询,并实施一套严格的规则,确定当前代码对标识符的访问权限
有什么角色知道了,现在就来讲讲他们三个是怎样来编译和执行的,就拿一个简单的代码来说
var a = 2
首先,编译器会看所在作用域是否有a,如果没有它就会生成一个a,接下来他就会生成代码提交给引擎
然后引擎拿到代码运行时它会去问作用域是否有这个a,如果有它就会把2赋值给a,如果作用域说没有,他就会接着去找,至于怎么找,下面再详细说。如果引擎怎么找也找不到a,他就会抛出一个异常。
三·LHS与RHS
要讲的这两个东西是引擎查找是的两种方式,L就是left,R就是right。下面就拿一段代码来具体理解
1 | function foo(a){ |
LHS是赋值操作的目标是谁(查找的目的是对变量进行赋值),RHS是赋值操作的源头是谁(查找目的是获取变量的值)
首先c=是赋值操作,所以进行一个LHS,再看调用foo(2)时,因为2是数值而不是变量所以我们不需要去查找他是谁,也就是不需要进行RHS,
再往下走,这个时候就要来到函数体,a我们不知道,所以要获取,就要对foo()进行RHS,然后传参使2赋值给了a(隐式赋值),那么a就进行了LHS。
再往下走,b=a,这是一个赋值操作所以b就是用了LHS,这个时候还是要查找a,那么就又进行了RHS
接下来需要注意的是,console是个对象,而log是console调用的一个函数,这个时候console是什么我们不知道,所以console要进行RHS,然后还要查找a,所以a也要进行一下RHS
再往下走,a+b中还是要查找a,b,所以要进行两次RHS
四·异常
我们为什么要知道LHS和RHS,就是因为引擎用这两种不同的方式会导致不同的处理方式
如果RHS查找怎么也找不到,那么它就会抛出一个ReferenceError的异常
而LHS如果查找不到但是他是在非严格模式下(禁止自动或隐性创建全局变量),那么他就会隐式地创建一个全局变量,如果他在严格模式下,他就会抛出一个TypeError
五·作用域嵌套
作用域嵌套其实就是关乎着引擎的查找方式。首先如果引擎在当前作用域没有找到想要的变量,他就会去上一级作用域去找,以此类推,可以把作用域们想象成一栋楼,当前作用域就在一楼,他嵌套的作用域(上级作用域)就以此升高,最高层就是全局变量,引擎也就找到全局变量为止了。
`
javascript
function foo(a){
console.log(a+b);
}
var b = 2;
foo(2);
}
就拿上面的代码来说,我想用b,但是作用域里没有,他就会去外层去找,这里也就是全局变量b了,结果也就可以正常的执行出来