任何一段JavaScript代码都对应一个作用域链,作用域链中存放一系列对象,代码中声明的变量将作为对象的属性存放。
在JavaScript的顶层代码中,作用域链由一个全局对象组成;当定义一个函数时,它保存一个作用域链,作用域链上有两个对象,一个是函数对象,一个是全局对象。
每当一个函数被调用时,会创建一个活动对象(也叫上下文对象),函数中的局部变量将作为该对象的属性存放。
当需要使用一个变量时,将从作用域链中逐个查找对象的属性。比如:要使用变量a,将先查找作用域中的第一个对象是否有属性a,如果有就使用;如果没有就查找作用域链中下一个对象的属性,以此类推。如果作用域链上没有任何一个对象含有属性 x,则认为这段代码的作用域链上不存在x,将抛出引用错误异常。
当函数调用完成后,如果没有其他引用指向为此次调用所创建的上下文对象,该对象将被回收。
var a = 100;
function f() {
var a = 200;
function g() {
return a;
}
return g;
}
console.log(f()());
上述代码运行,会输出200。
上述代码意味着,先执行 f(),得到该函数内嵌套的一个函数对象 g,然后调用这个嵌套的函数。
定义函数 f 时,它保存一个作用域链,作用域链上有两个对象,一个是函数对象,一个是全局对象,此时,全局变量 a 是全局对象的属性,和函数对象 f 无关。
执行函数 f 时,会创建一个活动对象,其中保存变量 a 作为函数 f 的属性而存在。而函数g嵌套定义在函数 f里,对其访问变量 a时,它没有变量 a,则继续往下查找函数 f。找到函数 f 的属性 a 并返回。因此,输出结果为 200。
这种函数将变量包裹起来,外部代码可以通过内嵌函数 g来访问函数 f 内的局部变量的方式,也称为闭包。