1.作用域是什么?
1.1 编译原理
- 分词/词法分析,将字符组成的字符串分解成有意思的代码块,这些代码块称为词法单元:
var a = 2;
// 代码会被分成右面这些词法单元:var、a、=、2、;
解析/语法分析,将词法单元流转换成一个由元素逐级嵌套所组成的代表了程序语法结构的树,"抽象语法树"(Abstract Syntax tree, AST)
代码生成,将AST转换为可执行代码的过程被称为代码生成。
当var a = 2;有某种方法将里面的AST转化为一组机器指令,用来创建一个叫做a的变量(包括分配内存等),并将一个值储存在a中。
对于JavaScript来说,大部分编译发生在代码执行前的几微秒。
1.2 理解作用域
- 引擎:从头到尾负责整个JavaScript程序的编译与执行过程。
- 编译器:负责语法分析及代码生成等。
- 作用域:负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。
总结:变量赋值:首先编译器会在当前作用域中声明一个变量,然后在运行时引擎会在作用域中查找该变量,找到及赋值。
- LHS查询:试图找到变量的容器本身,从而对其赋值。
- RHS查询:查找某个变量的值。
function foo(a) {
console.log(a); //2
}
foo(2)
步骤解析:
- 引擎为foo进行RHS引用
- 作用域给引擎这个foo的值。
- 引擎执行foo
- 引擎对a进行LHS引用
- 作用域把foo里面的形式参数a给引擎
- 2赋值给a
- 为console进行RHS引用
- 为a进行RHS引用
1.3 作用域嵌套
遍历嵌套作用域链:引擎从当前的执行作用域开始查找变量,找不到则到上一级去查找,当抵达最后一层全局作用域时,则强制停止。
1.4 异常
ReferenceError:RHS查询在所有嵌套作用域中无法遍寻到所需的变量,引擎就会抛出ReferenceError异常
TypeErroe: 对所操作的变量进行非法或者不合理操作