几乎所有编程语言最基本的功能之一,就是能够存储变量当中的值,并能在之后对这个值进行访问或修改。事实上,正是这种存储和访问变量的值的能力将状态带给了程序。
但是将变量引入程序会引起几个很有意思的问题,也正是我们将要讨论的:
这些变量住在哪里?换句话说,它们存储在哪里?最重要的是,程序需要时如何找到它们?
这些问题说明需要一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量。这套规则被称为作用域。
编译原理
尽管通常将JavaScript归类为“动态”或“解释执行”语言,但事实上它是一门编译语言。
但与传统的编译语言不同,它不是提前编译的,编译结果也不能在分布式系统中进行移植。
比起那些编译过程只有三个步骤的语言的编译器,JavaScript引擎要复杂得多。例如,在语法分析和代码生成阶段有特定的步骤来对性能进行优化,包括对冗余元素进行优化等。
首先,JavaScript引擎不会有大量的时间来进行优化,因为与其他语言不通,JavaScript的编译过程不是发生在构建之前的。
对于JavaScript来说,大部分情况下编译发生在代码执行前的几微妙的时间内。在我们所要讨论的作用域的背后,JavaScript引擎用尽了各种方法(比如JIT,可以延迟编译甚至实施重新编译)来保证性能最佳。
简单地说,任何JavaScript代码片段在执行前都要进行编译(通常就在执行前)。
理解作用域
演员表
首先介绍将要参与到对程序 var a = 2;进行处理的过程中的演员们,这样才能理解接下来
将要听到的对话。
- 引擎
从头到尾负责整个JavaScript程序的编译及执行过程。
- 编译器
引擎的好朋友之一,负责语法分析及代码生成等脏活累活
- 作用域
引擎的另一位好朋友,负责收集并维护由所有声明的标识符组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。
对话
当你看见var a=2;这段程序时,很可能认为这是一句声明。但我们的新朋友引擎却不这么看。
事实上,引擎认为这里有两个完全不同的声明,一个由编译器在编译时处理,另一个则由引擎在运行时处理。
变量的赋值操作会执行两个动作,首先编译器会在当前作用域中声明一个变量,然后在运行时引擎会在作用域中查找该变量,如果能够找到就会对它赋值。
编译器有话说
编译器在编译过程的第二步代码中生成了代码,引擎执行它时,会通过查找变量a来判断它是否已声明过。查找的过程由作用域进行协助,但是引擎执行怎样的查找,会影响最终的查找结果。
在上面的例子中,引擎会为变量a进行LHS查询。另外一个查找的类型叫作RHS.换句话说,当变量出现在赋值操作的左侧时进行LHS查询,出现在右侧时进行RHS查询。
讲的更准确一点,RHS查询与简单地查找某个变量的值别无二致,而LHS查询则是试图找到变量的容器本身,从而可以对其赋值。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。