词法作用域就是定义在词法阶段的作用域。换句话说,词法作用域是由你在写 代码时将变量和块作用域写在哪里来决定的,因此当词法分析器处理代码时会保持作用域 不变(大部分情况下是这样的)
-
引擎:
从头到尾负责整个js程序的编译及执行过程
-
编译器:
引擎的好朋友之一,负责语法分析及代码生成等
-
作用域:
引擎的另一好朋友,负责收集并维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当期执行的代码对这些标识符的访问权限
-
LHS查询:
查找的目的是对变量进行赋值
-
RHS查询:
查找的目的是获取变量的值
js引擎首先会在代码执行前对其进行编译,在这个过程中,像var a=2这样的声明会被分解成两个独立的步骤:
1.首先,var a在其作用域中声明变量,这会在最开始的阶段,也就是代码执行前进行;
2.接下来,a=2会查询(LHS查询)变量a并对其进行赋值;
eval和with会在运行时修改或创建新的作用域,以此来欺骗其他在书写时定义的词法作用域。
js引擎会在编译阶段进行数项的性能优化,其中有些优化项依赖于能够根据代码的词法进行静态分析,并预先确定所有变量和函数的定义位置,才能在执行过程中快速找到标识符。 但如果引擎在代码中发现了eval和with,它只能简单地假设关于标识符位置的判断都是无效的,因为无法在词法分析阶段明确的知道eval会接收到什么代码,这些代码会如何对作用域进行修改,也无法知道传递给with用来创建新词法作用域的对象内容到底是什么,
最悲观的情况是如果出现了 eval(..) 或 with,所有的优化可能都是无意义的,因此最简 单的做法就是完全不做任何优化。
如果代码中大量使用 eval(..) 或 with,那么运行起来一定会变得非常慢。无论引擎多聪 明,试图将这些悲观情况的副作用限制在最小范围内,也无法避免如果没有这些优化,代 码会运行得更慢这个事实。