你不知道的Javascript(上卷)读书笔记之二 ---- 词法作用域

在前一篇文章中,我们把作用域定义为”管理、维护变量的一套规则”,接下来是时候来深入讨论一下Js的作用域问题了,首先我们要知道作用域一般有两种主要的工作类型,一种是词法作用域,一种是动态作用域, Javascript采用的是词法作用域, 关于动态作用域的有兴趣的可以自行Google。

1.词法阶段

          首先我们要理解”词法阶段”这个词语,我们已经了解到Js存在一个编译阶段,编译阶段的第一步就是分词/词法分析,我们可以简称为”词法阶段”

          简单来说,词法作用域就是定义在词法阶段的作用域,词法作用域是你在写代码时把变量和块作用域写在哪里来决定的,词法分析器处理代码后,在大部分情况下会保持作用域不变。我们需要注意以下几点:

          a.当引擎需要查询变量时,总是从当前作用域开始查找

          b.作用域查找会在找到第一个匹配的标识符时停止

          c.遮蔽效益(内部的标识符”遮蔽”了外部的标识符)

          d.全局变量会自动成为全局对象的属性,通过这种技术可以间接的访问那些被遮蔽的全局变量

          e.无论函数在哪里被调用,也无论它如何被调用,它的词法作用域也只由它被声明的位置决定

          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() 会在运行时修改或创建作用域,以此来欺骗其他词法作用域。但是会极大的降低代码的运行效率,有可能之前对代码进行的优化会全部无效,使得代码的运行变得很慢。

posted @ 2016-12-05 20:25  bug你奏凯  阅读(315)  评论(0编辑  收藏  举报