机缘
今儿又有人问我闭包的原理,我是连写代码带比划的和他说了半天,
可看他依然似懂非懂的表情,我也是慢慢的挫败感.
解释几个概念
- 函数执行是,每个执行上下文都会一个包含其中变量的对象.
- 全局上下文中叫做变量对象,代码执行期间始终存在.
- 函数局部上下文叫活动对象,只在函数执行期间存在.
- 上下文之的就是某段代码的运行环境,在执行前的几毫秒生成,可参考另一篇文章上下文就是煮一碗泡面
- 作用域链:上下文代码执行时,利用变量对象创建的,决定了各级上下文中代码访问变量和函数的顺序.
普通函数
function compare(value1,value2){
if(value1<value2){
return -1;
}else if(value1>value2){
return 1;
}else{
return 0;
}
}
let result = compare(5,10);
console.log(result);
分析一波
- compare() 函数在全局上下中调用,第一次调用compare时,会为它创建一个活动对象.
- 活动对象中包括,value1,value2和arguments等值.
- 该活动对象是compare()作用域链中的第一个对象.
- 而全局上下文的变量对象是compare作用域链上的第二个对象.其中包含this,result和compare()
图示如下
- 函数内部代码在访问变量时,就会从给定作用域链中查找.
- 函数执行完毕局部活动对象被销毁内存只剩下全局变量对象,不过闭包就不一样.
闭包函数
function createComparisonFunction(){
return function (value1,value2){
if(value1<value2){
return -1;
}else if(value1>value2){
return 1;
}else{
return 0;
}
}
}
let compare = createComparisonFunction('name');
let result = compare({name:'Nichoias'},{name:'Matt'})
分析一波:
- createComparisonFunction返回闭包后,它的作用域链被初始还为包含createComparisonFunction的活动多对象和全局变量对象.
- 如此,匿名函数就可以访问createComparisonFunction可以访问的所有变量.
- 不好的地方就是它的活动对象不能在它执行完毕时销毁,因为匿名函数的作用域链仍然对它有引用.
- 一直到匿名函数被销毁,其活动对象才会被销毁.
优化
// 解除对函数的引用,这样就可以释放内存了
let compare = createComparisonFunction('name');
compare = null;
- 设置为null,解除对函数的引用,从而让垃圾回收程序可以将内存释放出来.
- 作用域链也会被销毁.
注意
- 闭包会保留相关(自己,及父级)函数的作用域,所以比其他函数更占用内存.
- 所以必须在十分必要的时候采去使用.