执行上下文与作用域
要解释这个问题首先就要了解一个概念,执行上下文,我们看看红宝书上如何解释:变量或者函数的上下文决定了它们可以访问哪些数据以及它们的行为,每个上下文都有一个关联的变量对象,而这个上下文中定义的所有变量和函数都存在于这个对象上,听的有些云里雾里?没关系我们这里先按下不表,听了之后的介绍我们再来回头看看。
全局上下文,有点类似全局变量,是常说的window对象,所有通过var定义的全局变量和函数都会成为window对象的属性和方法,而使用let和const的顶级声明不会定义在全局上下文之中,这也是let和const比var“高级”的第一个表现,
而在代码执行时,会创建一个变量对象的作用域链,可以理解为联系代码的一条“绳索”代码的执行顺序需要按照这条绳索向前,代码正在执行的上下文的变量对象始终位于作用域的最前端,而如果上下文是函数,则其活动对象用作变量对象,而活动对象又是什么?我们简单介绍一下:
活动对象:在js中,当一个函数被调用的时候,就会产生一个特殊的对象,这个对象就是活动对象,这个对象中包含了参数列表和arguments对象等属性,由于活动对象是变量对象的特例,因此它包含变量对象所有的属性如变量定义,函数定义等,函数被调用时活动对象被创建
而全局上下文的变量始终是作用域链的最后一个变量对象,总的来说这么长一段话只要记得:代码正在执行的上下文的变量对象始终位于作用域的最前端,全局上下文的变量始终是作用域链的最后一个变量对象,这么一句就行了,那这又有什么用呢?我们看个例子(没错,还是红宝书上的):
<script>
var color = "blue";
function changeColor(){
let anotherColor = "red";
function swapColors(){
let tempColor = anotherColor;
anotherColor = color;
color = tempColor;
//此处可以访问color,anotherColor,tempColor
}
swapColors()
//此处可以访问anotherColor,color,访问不到tempColor
}
changeColor()
//只能访问color
</script>
我们从上到下梳理一下作用域链,先是window,然后是color,changeColor(),anotherColor,swapColors(),最后是tempColor,
根据我们刚刚的那句话,正在执行的上下文的变量对象始终位于作用域的最前端,全局上下文的变量始终是作用域链的最后一个变量对象,同时内部上下文可以通过作用域链访问外部上下文的一切,外部上下文无法访问内部上下文中的任何东西,swapColors()的局部上下文包含自己的变量对象,changeColor()的变量对象,还有全局变量对象,因此我们看到在函数中可以访问这三个变量对象的次级上下文,也既color,anotherColor,tempColor,下面的也是同理,这也解释了局部变量的访问问题。