每个javascript函数都是一个对象,有着自己的属性,有些是我们可以访问到的,有些只供javascript引擎存取,例如[[scope]].[[scope]]就是我们常说的作用域,存储了执行期上下文的集合,所有的执行期上下文呈链式连接,也就是作用域链
作用域:每当函数执行前一刻都会生成一个自己的内部环境,也就是作用域,每次函数执行时生成的作用域都是独一无二的,当函数执行完毕后这个环境就会被销毁
<script>
function a(){
var b = 1;
}
a();
<script>
看着一段简单的代码,a函数被定义在全局里面,当a函数被定义时他会生成一个GO对象(Global Object),里面存储了全局的执行期上下文,放在a函数作用域链的顶端.
当a函数执行时,又会生成一个AO对象(ActivationObject),里面存储着a内部的执行期上下文,放在作用域链的顶端。层层递进,从而形成了作用域链,当函数执行时,就会沿着作用域链的顶端寻找他所需要的信息。
function a(){
var b = 1;
function c(){
b = 2;
}
c();
console.log(b);
}
a();
来看这一段,先分析一下他们的作用域链,a函数定义时生成一个GO对象,放在自己作用域链的顶端,当
a函数执行时又会生成一个AO对象,AO,GO依次存放于[[scope]]中。当c函数定义时,他生成一个AO对象,里面放着时a的作用域链,当c被执行时又会生成一个自己的AO,放在作用域链的顶端,也就是:0:cAO 1:aAO 2GO,这样依次向下。这里有一个问题,c的作用域链里面存放着的aAO是否是a真正的AO呢,答案是是的,因为a只形成了一个自己的AO,c既然站在a的身体里看世界,他拿的是a的东西,自然看到的用的是a的AO,也就是说,在c函数里面修改a函数的变量会使变量值发生改变,当a再次访问这个变量时已经是修改后的值了。
这就是作用域链的基本概念与解释,归纳一下重点:
-
函数定义时拿上级函数的AO放在作用域链顶端
-
函数执行时生成自己的AO放在作用域链顶端
-
函数执行是按照从上往下的顺序在自己的作用域链里面查找变量
-
内部函数可修改外部函数的值,用的就是外部函数的AO
-
函数每次执行完毕就会销毁一次自己的作用域链,隐式销毁,所以每当函数执行就会重新创建一次。
当js比较复杂是当然也是遵循这个规律,只是形成的作用域链比较长