关于理解JavaScript到底是如何工作的,其中最重要的概念之一就是作用域。
域,顾名思义是一个区域的意思,在区域中肯定会存在一些有用的"东西"。那么在JavaScript的域中就会存放一些你所声明的变量,函数,对象等等。在该区域中存储的值都会受到一套规则进行管理,那么我们可以把这套规则叫做作用域。
JavaScript是一种解释性语言,但是在JavaScript中,代码在运行之前都会进行一个预编译的过程,这个过程通常执行在代码执行之前,而且编译的过程可能在几微秒之内。
在JavaScript解析的过程中,有三个重要的角色:引擎、编译器、作用域。
- 引擎主要负责的是JavaScript的编译和执行。
- 编译器主要负责的是对JavaScript代码的词法分析,语法分析的过程。
- 作用域则是维护所有的标识符,并对其进行一系列的查询,且实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。
那么编译器是如何和另外两个协同工作的呢?
当你代码中声明一个变量的时候,它会首先访问作用域中是否已经存在了该变量,如果有则会忽略该声明操作,如果没有的话,则会要求作用域在当前的作用域中生命一个新的变量,并且命名为你所指定的标识符。
执行完以上这一套过程后,编译器会为引擎生成所需要执行的代码。如果代码中有一段赋值操作,引擎首先会在当前作用域中找是否有该变量,如果有则进行赋值,如果没有则会向上继续查找该变量。最后如果没找到则会抛出异常,如果找到的话则正常执行。
上面我们说到了引擎会在执行代码的时候找你所声明的变量。那么找的方式会有以下两种,一个是LHS查询一个是RHS查询。顾名思义,L则是从左边进行查询,R则是从右边进行查询,那么是从哪个的左边和右边进行查询呢?这里所说的查询是从赋值操作的左边和右边进行查询。
这样说大家可能不太懂这个LHS和RHS到底有什么区别,首先,简而言之,当你所查询的变量在等号左侧的时候进行LHS查询,当你所需要查询的变量在等号右侧的时候进行的是RHS查询:
var a = 10; //这里引擎对a的查询是LHS
var b = a; //这里引擎对a的查询是RHS
更准确的说,LHS的查询是查到某个变量的容器本身,从而可以对其进行赋值。RHS的操作则是查询到某个变量,并且获取到他的原值。
为什么要区分这两个看起来似乎没有区别的查询操作呢?因为在变量还未声明的时候这两个操作的行为是不一样的。如果一个变量在任何的作用域中都未声明,在 进行LHS操作后会在全局的情况下创造一个该变量,如果是RHS操作的话,最后没找到该变量则会抛出异常。
作用域嵌套,当一个块或者函数嵌套在另一个块或者函数中时,就发生了作用域嵌套。因此,当在当前作用域中无法找到某个变量的时候,引擎就会在外层嵌套的作用域中继续查找,直到查找到该变量或抵达最外层的作用域为止。
总结:
- 作用域可以看成是一套用于在何处,如何查找变量的规则。
- 引擎查找的方式有LHS和RHS两种方式。
- JS会在执行前进行编译,如果是一个var a = 1的操作, var a 在其作用域声明变量。a = 1会查询变量并对其赋值。