简单来说:闭包就是在函数外部读取到了函数内部的变量,就形成了闭包。
在JavaScript中,没有块级作用域,只有函数作用域;因此,通常情况下只有在函数内部才能访问到该函数内部的变量,如下代码会报错:
function test() {
var a = '张三';
}
console.log(a); // a is not defined
那么怎么样才能访问test函数内部的变量呢,看如下代码:
function test(){
var a = '张三';
return function(){
return a;
}
}
console.log(test()()); // '张三'
通过返回一个函数的方式,而这个函数属于test内部函数,可以正常访问到变量a,从而达到在外部访问函数内部变量的效果。
那么问题来了,这样做有什么用呢?来看下如下的代码:
function test(){
var n = 1;
var add = function(){
n++;
return n;
};
return add;
}
var addFunc = test();
console.log(addFunc()); // 2
console.log(addFunc()); // 3
当第一次执行test函数时,返回add函数体并赋值给addFunc,然后执行addFunc方法得到的n是2;再次执行addFunc方法得到的却是3,这里的n并没有重新从1开始计算,也就是说,这里的n累加了之后被缓存起来了。这就是闭包的作用:缓存变量。
这里我举一个更加详细一点的例子来说明闭包的作用:我是一个餐馆的老板,这个餐馆的纯收入是变量s,s = 营收 - 花费,s变量会随着营收和花费更新,参考以下代码:
!function ys(){
var s = 0; // 纯收入
window.add = function(n){ // 营收
s += n;
return s;
};
window.reduce = function(m){ // 花费
s -= m;
return s;
};
}();
window.add(10); // s = 10;
window.add(100); // s = 110;
window.reduce(100); // s = 10;
通过局部函数add和reduce来操作s变量,s变量在这两个函数中是共享的;同时因为s是局部变量,外部不能直接修改,所以这个变量被保护了起来。
以上是我对闭包的理解,总结以下:
- 闭包让我们可以访问到函数内部的变量;
- 闭包让这些内部的变量被缓存下来;
- 因为闭包会使得变量被缓存下来,所以不能滥用,不然可能在会造成内存泄露,解决方法是,在退出函数之前,将不使用的局部变量全部删除。