词法作用域
作用域共有两种主要的工作模型。第一种是最为普遍的,被大多数编程语言所采用的词法作用域。另外一种叫作动态作用域,仍有一些编程语言在使用(如Bash脚本、Perl中的一些模式等)
词法阶段
简单地说,词法作用域就是定义在词法阶段的作用域。换句话说,词法作用域就是由你在写代码时将变量和块作用域卸载哪里来决定的,因此当词法分析器处理代码时会保持作用域不变(大部分情况下是这样的)。
在多层的嵌套作用域中可以定义同名的标识符,这叫“遮蔽效应”。(内部的标识符遮蔽了外部的标识符)
抛开遮蔽效应,作用域查找始终从运行时所处的最内部作用域开始,逐级向外或者说向上进行,直到遇到第一个匹配的标识符为止。
全局变量会自动成为全局对象(比如浏览器中的window对象)的属性,因此可以不直接通过全局对象的词法名称,而是间接地通过对全局对象属性的引用来对其进行访问。可以通过类似
window.a
来访问那些被同名变量a
所遮蔽的全局变量。
欺骗词法
在javascript中有两种机制来实现在运行时“修改”(也可以说欺骗)词法作用域。但是社区普遍认为使用这两种机制并不是什么好的主意。-欺骗词法作用域会导致性能下降。
eval
函数可以接受一个字符串为参数,并将其中的内容视为好像在书写时就存在于程序中这个位置的代码。就是动态插入一段好像在程序书写时候就存在当前位置的一段代码一样。with
关键字看起来比较难懂。但是简单的来阐述他的话就是:with
可以将一个没有或有多个属性的对象处理为一个完全隔离的词法作用域,因此这个对象的属性也会被处理为定义在这个作用域中的词法。
小结
JavaScript引擎会在编译阶段进行数项的性能优化。其中有些优化依赖于嫩个够更具代码的词法进行静态分析,并预先确定所有变量和函数的定义位置,才能在执行过程中快速找到标识符。所以当代码中大量使用eval(..)
或with
,引擎的优化可能就是无意义的,程序运行起来也会十分慢。
词法作用域意味着作用域是由书写代码时函数声明的位置来决定的。