首先要弄清楚什么作用域?
作用域其实就是一套规则,用来存储和查找程序中的变量。这套规则可以管理引擎在当前作用域以及嵌套的子作用域中根据标识符来查找变量。
要理解词法作用域,首先要知道什么是词法。词法化是大部分标准语音编译器的第一个工作阶段,主要对源代码中的字符进行检查,然后将其分解成有意义的代码块。而词法作用域就是定义在词法化阶段的作用域。当你写下块作用域和变量时,已经决定了词法作用域就在那里,通常情况下这个作用域是不会变的(欺骗词法除外,下面会将会介绍)。
作用域结构以及相互之间的位置为引擎提供了足够的位置信息,方便其查找标识符,作用域查找到第一个标识符就会停止,其实说白了,作用域就是为引擎服务的,引擎需要什么,有的情况下就乖乖提供好了。
对于函数,无论其在哪里调用,如何调用,其词法作用域都有其函数声明时所处的位置决定。
欺骗词法
欺骗词法什么意思呢?上面我们提到过,正常的词法作用域是由函数声明的时候决定的,如果要想在运行时改变呢?这里有两个方法,一个用eval,一个用with,也代表两种机制,我们看下其原理。
我们很清楚,eval(...)中可以传入一段字符串作为参数,字符串是一段代码,eval所在的位置就是代码段执行的位置,这样就会修改其所在的作用域。
性能问题
利用eval固然可以实现想要的功能,但是,由于JavaScript 引擎会在编译阶段进行数项的性能优化,有些优化主要依据词法分析得到的变量和函数的位置,才能在执行过程中快速找到标识符。在遇到eval时,在词法分析阶段由于无法判断其里面的代码,所以就会简单的认为没有优化的必要。如果程序中遇到大量的eval,性能肯定是会降低的,所以不建议用eval。