闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套函数中实现的。
function compare(value1, value2) {
if(value1 === value2) return 0;
return value1 > value2 ? 1 : -1;
}
let result = compare(5, 10);
第一次调用compare()时,会为它创建一个包含arguments、value1和value2的活动对象,这个对象是作用域链上的第一个对象。而全局上下文的变量对象则是compare()作用域链上的第二个对象,其中包含this、result和compare。
函数执行时,每个执行上文中都会有一个包含其中变量的对象。全局上下文中叫变量对象,它会咋代码执行期间始终存在。而函数局部上下文中叫活动对象,只在函数执行期间存在。在定义compare()
函数时,就会为他创建作用域链,预装载全局变量对象,并保存在内部的**[[Scope]]中。在调用这个函数的时候,会创建相应的执行上下文,然后通过复制函数的[[Scope]]**来创建其作用域链。接着会创建爱你函数的活动对象并将其推入作用域链的前端。
这个例子中,compare()
函数执行上下文的作用域链中有两个变量对象:局部变量对象和全局变量对象。作用域链其实是一个包含指针的列表,每个指针分别指向一个变量对象,但物理上并不会包含相应的对象。
let compare = createComparisonFunction('name');
let result = compare({name: 'Nicholas'}, {name: 'Matt'});
在以上代码中,createComparisonFunction()
返回匿名函数后,他的作用域链被初始化微包含createComparisonFunction()
的活动对象和全局变量对象。这样匿名函数就可以访问到它能访问的全部变量对象。但是有个有意思的副作用是,createComparisonFunction()
的活动对象并不能在它执行完毕后销毁,因为匿名函数中仍然保持着对它的引用。直到匿名函数被销毁后才会被销毁;这里可以把compare
的值设置为等于null,会接触对函数的引用,从而让垃圾回收程序可以将内存释放掉。