JS作用域链

作用域链的执行:如图所示,当在查找变量的定义时,JavaScript引擎首先在局部执行环境对象上查找。如果没有定义,则跳出作用域链,到创建它的执行环境中去,并且在该执行环境对象中查找变量的定义,以此类推,直到找到定义或者到达全局作用域为止。

为了演示作用域链,下面我们来看一份例子,下面的代码清单将会依次打印下面的内容:
-I am here to save the day
-regular_joe is assigned
-undefined

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var regular_joe = 'I am here to save the day'; //在全局作用域里,设置regular_joe

//logs 'I am here to save the day'
console.log(regular_joe); //调用作用域:全局。作用域链中的最近匹配:全局的regular_joe
function supermax(){
var regular_joe = 'regular_joe is assigned';

//logs 'regular_joe is assigned'
console.log(regular_joe); //调用作用域:全局->supermax(),作用域链中的最近匹配:在supermax()中定义的regular_joe

function presion(){
var regular_joe;
console.log(regular_joe); //调用作用域:全局->supermax()->presion(),作用域链中的最近匹配:在presion()中定义的regular_joe
}

//logs 'ubdefined'
presion();
}
supermax();

在运行期,JavaScript会检索作用域层级来解析变量名,它从当前作用域开始,然后按它的查找方式回到顶级的作用域,即window(浏览器)或者global(node.js)对象,它找到的第一次匹配并停止查找。注意,这意味着在层级更深的嵌套作用域中的变量,会使用它们的当前作用域替换更加全局的作用域,从而隐藏更加全局的作用域中的变量。

我们来详细地解释下这段代码的执行过程:
(1)清单中的第一处console.log(regular_joe)调用在全局作用域里面。JavaScript从全局执行环境对象上开始查找regular_joe属性。它找到了一个值为I am here to save the day,并使用了这个值。
(2)清单中的第二处console.log(regular_joe)调用在supermax的执行环境中。JavaScript从supermax执行环境对象上开始查找regular_joe属性。它找到了一个值为regular_joe is assigned,并使用了这个值。
(3)清单中的第三处console.log(regular_joe)调用在supermax的执行环境内的prison执行环境中。JavaScript从prison执行环境对象上开始查找regular_joe属性。它找到了一个但未被赋值,所以为undefined,并使用了这个值。

例如下面这段代码它的执行结果为:输出三次-I am here to save the day,原因是我们只在全局作用域汇总定义了这个变量,所以当JavaScript在当前作用域中找不到该变量的定义时,会回溯到上一级继续查找该变量,直到查找到全局作用域,最终找到了就使用这个值,若最终还是找不到则为undefined

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var regular_joe = 'I am here to save the day'; //在全局作用域里,设置regular_joe

//logs 'I am here to save the day'
console.log(regular_joe); //调用作用域:全局。作用域链中的最近匹配:全局的regular_joe
function supermax(){
//logs 'I am here to save the day'
console.log(regular_joe); //调用作用域:全局->supermax(),作用域链中的最近匹配:全局中定义的regular_joe

function presion(){
console.log(regular_joe); //调用作用域:全局->supermax()->presion(),作用域链中的最近匹配:在全局中定义的regular_joe
}

//logs 'I am here to save the day'
presion();
}
supermax();