我们说过 作用域 是通过标识符名称查询变量的一组规则。但是,通常会有多于一个的 作用域 需要考虑。
就像一个代码块儿或函数被嵌套在另一个代码块儿或函数中一样,作用域被嵌套在其他的作用域中。所以,如果在直接作用域中找不到一个变量的话,引擎 就会咨询下一个外层作用域,如此继续直到找到这个变量或者到达最外层作用域(也就是全局作用域)。
考虑这段代码:
function foo(a) {
console.log( a + b );
}
var b = 2;
foo( 2 ); // 4
b
的 RHS 引用不能在函数 foo
的内部被解析,但是可以在它的外围 作用域(这个例子中是全局作用域)中解析。
所以,重返 引擎 和 作用域 的对话,我们会听到:
引擎:“嘿,
foo
的 作用域,听说过b
吗?我得到一个它的 RHS 引用。”作用域:“没有,从没听说过。问问别人吧。”
引擎:“嘿,
foo
外面的 作用域,哦,你是全局 作用域,好吧,酷。听说过b
吗?我得到一个它的 RHS 引用。”作用域:“是的,当然有。给你。”
遍历嵌套 作用域 的简单规则:引擎 从当前执行的 作用域 开始,在那里查找变量,如果没有找到,就向上走一级继续查找,如此类推。如果到了最外层的全局作用域,那么查找就会停止,无论它是否找到了变量。
建筑的隐喻
为了将嵌套 作用域 解析的过程可视化,我想让你考虑一下这个高层建筑。
这个建筑物表示我们程序的嵌套 作用域 规则集合。无论你在哪里,建筑的第一层表示你当前执行的 作用域。建筑的顶层表示全局 作用域。
你通过在你当前的楼层中查找来解析 LHS 和 RHS 引用,如果你没有找到它,就坐电梯到上一层楼,在那里寻找,然后再上一层,如此类推。一旦你到了顶层(全局 作用域),你要么找到了你想要的东西,要么没有。但是不管怎样你都不得不停止了。