一、编译原理
Javascript程序中的一段代码在执行以前经历三个步骤,统称为“编译”。
(1)分词/词法分析
(2)解析/语法分析
(3)代码生成
二、LHS查询和RHS查询
LHS和RHS的含义是“赋值操做的左侧或右侧”并不必定意味着就是“ =赋值操做符的左侧或右侧”。
当变量出如今赋值操做的左侧时进行LHS查询,出如今赋值操做的右侧时进行RHS查询
RHS查询与简单地查找某个变量的值别无二致,而LHS查询则是试图找到变量的容器自己,从而能够对其赋值。
若是查找目的是对变量进行赋值,那么就使用LHS查询;若是目的是获取变量的值,就会使用RHS查询。
考虑如下代码:
其中对a的引用是一个RHS引用,由于这里a并无赋予任何值。相应的,须要查找并取得a的值,这样才能将值传给console.log(…).
相比之下,例如:
a=2
这里对 a 的引用则是 LHS 引用,由于实际上咱们并不关心当前的值是什么,只是想要为 =2 这个赋值操做找到一个目标。
考虑下面的程序,其中既有 LHS 也有 RHS 引用:
function foo(a){
console.log(a);//2
}
foo(2);
最后一行 foo(..) 函数的调用须要对 foo 进行 RHS 引用,意味着“去找到 foo 的值,并把它给我”。而且 (..) 意味着 foo 的值须要被执行,所以它最好真的是一个函数类型的值。
代码中隐式的 a=2 操做可能很容易被忽略掉。这个操做发生在 2 被看成参数传递给foo(..) 函数时, 2 会被分配给参数 a 。为了给参数 a (隐式地)分配值,须要进行一次LHS 查询。
这里还有对 a 进行的 RHS 引用,而且将获得的值传给了 console.log(..) 。 console.log(..) 自己也须要一个引用才能执行,所以会对 console 对象进行 RHS 查询,而且检查获得的值中是否有一个叫做 log 的方法。
三、做用域嵌套
当一个块或函数嵌套在另外一个块或函数中时,就发生了做用域的嵌套。遍历嵌套做用域链的规则很简单:引擎从当前的执行做用域开始查找变量,若是找不到,就向上一级继续查找。当抵达最外层的全局做用域时,不管找到仍是没找到,查找过程都会中止。
四、 异常
由于在变量尚未声明(在任何做用域中都没法找到该变量)的状况下,这两种查询的行为是不同的。
考虑以下代码:
function foo(a) {
console.log( a + b );
b = a;
}
foo( 2 );
报错:Uncaught ReferenceError: b is not defined
‘b=a’不是变量声明,预编译过程当中不会将其提早
第一次对b进行RHS查询时是没法找到改变量,也就是说,这是一个“未声明”的变量,由于在任何相关的做用域中都没法找到它。
若是 RHS 查询在全部嵌套的做用域中遍寻不到所需的变量,引擎就会抛出 ReferenceError异常。值得注意的是, ReferenceError 是很是重要的异常类型。