我们说过 作用域 是通过标识符名称查询变量的一组规则。但是,通常会有多于一个的 作用域 需要考虑。

就像一个代码块儿或函数被嵌套在另一个代码块儿或函数中一样,作用域被嵌套在其他的作用域中。所以,如果在直接作用域中找不到一个变量的话,引擎 就会咨询下一个外层作用域,如此继续直到找到这个变量或者到达最外层作用域(也就是全局作用域)。

考虑这段代码:

  1. function foo(a) {
  2. console.log( a + b );
  3. }
  4. var b = 2;
  5. foo( 2 ); // 4

b 的 RHS 引用不能在函数 foo 的内部被解析,但是可以在它的外围 作用域(这个例子中是全局作用域)中解析。

所以,重返 引擎作用域 的对话,我们会听到:

引擎:“嘿,foo作用域,听说过 b 吗?我得到一个它的 RHS 引用。”

作用域:“没有,从没听说过。问问别人吧。”

引擎:“嘿,foo 外面的 作用域,哦,你是全局 作用域,好吧,酷。听说过 b 吗?我得到一个它的 RHS 引用。”

作用域:“是的,当然有。给你。”

遍历嵌套 作用域 的简单规则:引擎 从当前执行的 作用域 开始,在那里查找变量,如果没有找到,就向上走一级继续查找,如此类推。如果到了最外层的全局作用域,那么查找就会停止,无论它是否找到了变量。

建筑的隐喻

为了将嵌套 作用域 解析的过程可视化,我想让你考虑一下这个高层建筑。

嵌套的作用域 - 图1

这个建筑物表示我们程序的嵌套 作用域 规则集合。无论你在哪里,建筑的第一层表示你当前执行的 作用域。建筑的顶层表示全局 作用域

你通过在你当前的楼层中查找来解析 LHS 和 RHS 引用,如果你没有找到它,就坐电梯到上一层楼,在那里寻找,然后再上一层,如此类推。一旦你到了顶层(全局 作用域),你要么找到了你想要的东西,要么没有。但是不管怎样你都不得不停止了。