1.作用域
JavaScript是一门编译语言。(动态、解释执行),不是提前编译的(编译过程不是发生在构建之前),执行前编译,编译结果也不能在分布式系统中进行移植。
程序中的一段源代码在执行前会经历三个步骤,统称为编译:
-
分词/词法分析(区别在进行的方式有状态还是无状态)
将字符组成的字符串分解成有意义的代码块(词法单元)
-
解析/语法分析
词法单元流(数组)=>抽象结构树AST(代表程序语法结构)
-
代码生成
将AST转换为可执行代码的过程。
2. var a =2;
-
引擎
编译及执行过程
-
编译器
语法分析及代码生成
-
作用域
确定当前执行的代码对声明的标识符的访问权限
var a =2;
-
编译器在编译时处理
在当前作用域中声明一个变量,如果之前没有声明过分解成词法单元-->解析成树结构--->代码生成
-
引擎在运行时处理
引擎在作用域中查找该变量,如果能找到就对它赋值一个赋值操作的左侧和右侧。
编译器可以在代码生成的同时处理声明和值的定义。
-
LHS查询
变量出现在赋值操作的左侧,试图找到变量的容器本身,从而可以对其赋值,赋值操作的目标。
LHS查询不到,非严格模式下,在全局作用域中创建该变量,并将其返还给引擎。严格模式禁止自动或隐式地创建全局变量,查询不到,抛类似ReferenceError异常。
-
RHS查询
(非左侧,取得它的原值)变量出现在赋值操作的右侧,查找某个变量的值,赋值操作的源头。
RHS查询不到,引擎抛出ReferenceError异常。
异常:
- ReferenceError同作用域有关
- TypeError作用域判别成功,对结果的操作非法或不合理。
-
3.作用域嵌套
遍历嵌套作用域:从当前作用域(执行作用域)开始向上级作用域查找。作用域查找会在找到第一个匹配的标识符时停止。
“遮蔽效应”,内部的标识符遮蔽了外部的标识符。
全局变量被遮蔽,可通过引用全局对象的属性访问window.a
4.词法作用域
-
词法阶段
词法作用域:定义在词法阶段的作用域。
函数的词法作用域都只由函数被声明时所处的位置决定。
大部分情况下,词法分析器处理代码时会保持作用域不变。
-
词法作用域查找
只会查找一级字符
-
对象属性访问规则
-
-
欺骗词法
欺骗词法作用域会导致性能下降。引擎无法在无法在编译时对作用域进行查找进行优化。
-
eval(...)
参数:字符串
将传入的内容视为好像在书写时(词法期)就存在于程序中这个位置的代码,修改词法作用域的环境。
通常被用来执行动态创建的代码,在运行期修改书写期的词法作用域。严格模式下,无法修改所在的作用域。
-
with
重复引用同一个对象中的多个属性的快捷方式。
正常的var声明不会被限制在块的作用域。
严格模式禁止。
-