在前一篇文章中,咱们把做用域定义为”管理、维护变量的一套规则”,接下来是时候来深刻讨论一下Js的做用域问题了,首先咱们要知道做用域通常有两种主要的工做类型,一种是词法做用域,一种是动态做用域, Javascript采用的是词法做用域, 关于动态做用域的有兴趣的能够自行Google。函数
1.词法阶段性能
首先咱们要理解”词法阶段”这个词语,咱们已经了解到Js存在一个编译阶段,编译阶段的第一步就是分词/词法分析,咱们能够简称为”词法阶段”优化
简单来讲,词法做用域就是定义在词法阶段的做用域,词法做用域是你在写代码时把变量和块做用域写在哪里来决定的,词法分析器处理代码后,在大部分状况下会保持做用域不变。咱们须要注意如下几点:对象
a.当引擎须要查询变量时,老是从当前做用域开始查找ip
b.做用域查找会在找到第一个匹配的标识符时中止作用域
c.遮蔽效益(内部的标识符”遮蔽”了外部的标识符)字符串
d.全局变量会自动成为全局对象的属性,经过这种技术能够间接的访问那些被遮蔽的全局变量it
e.不管函数在哪里被调用,也不管它如何被调用,它的词法做用域也只由它被声明的位置决定io
f.词法做用域之会查找一级标识符,好比a、b、c。若是代码中引用了foo.bar.baz,词法做用域只会试图查找foo标识符,而后在使用对象属性访问规则进行对bar以及baz的访问编译
2.欺骗词法
咱们有时可使用一些语句对词法做用域进行欺骗,可是要注意的一点:欺骗词法做用域会致使性能降低
2.1 eval()
eval() 接受一个字符串参数,将这段字符串视做Javascript执行
在严格模式下,eval()中的代码有本身的词法做用域,所以其中的声明没法修改做用域外的代码的效果,而在非严格模式下,eval()中的代码能够修改eval()方法所在的做用域,即eval()方法中的全部声明与eval()方法处于同一个词法做用域,于是能够修改最终的效果。
new Function(...) 相似,将对传入的字符串动态生成函数,所以不做过多阐述。
2.2 with()
with(obj){ … } 实质上是建立了或者指向了obj中的词法做用域,在这个做用域中,全部的声明在被引擎执行时,都会在这个做用域中查找,若是查找不到,会在obj的上一层做用域继续查找,可是,当若是一直到顶层的全局做用域尚未找到时,会建立一个全局变量。而且,with在严格模式下被彻底禁止运行。
2.3 性能
eval() 和 with() 会在运行时修改或建立做用域,以此来欺骗其余词法做用域。可是会极大的下降代码的运行效率,有可能以前对代码进行的优化会所有无效,使得代码的运行变得很慢。