闭包的概念
在一个函数内定义一个内部函数,并将内部函数返回,即使该外部函数已经执行结束了,但是内部函数引用外部函数的变量依然保存在内存中,我们就把这些变量的集合称为闭包(或者将内部函数成为闭包)。
也有些人定义闭包的概念为:在一个函数内部定义一个函数,那么这个内部函数就被称为“闭包”。
function f1(){
var a1=1;
function f2(){
console.log(a1)
}
return f2
}
let result=f1()
result();//1
f2被称为闭包
闭包的作用
- 通过闭包,外部环境可以访问到函数里的变量
- f1中被f2访问的变量,始终存在内存中。形成f2的专属变量背包。
- 使用闭包,内部函数变量不会污染外部变量,规避冲突
闭包的副作用
- 变量常驻内存,造成内存溢出,所以在不使用时,记得清空。
- 解决方案:在不用时记得即使清空变量
执行环境及作用域链
要理解闭包,首先要对js的执行环境和作用域有了解
- 每个函数有一个执行环境,一个执行环境关联一个变量对象,变量对象的集合叫做作用域链。
- 作用域链的前端是当前的执行代码所在的变量对象,下一个对象是外部函数,一直延续到全局变量。
- 标识符解析是沿着作用域链从前端开始逐级回溯的过程。
- 代码执行完毕后,所在的环境会被销毁,web中全局执行环境是window对象,全局环境会在应用程序退出时被销毁。
闭包的应用
img对象经常用于数据上报,如下:
var report = function(src) {
var img = new Image();
img.src = src;
}
report('http://xxx.com/xxx.png');
这段代码在运行时,发现在一些低版本浏览器上存在bug,会丢失部分数据上报,原因是img是report函数中的局部变量,当report函数调用结束后,img对象随即被销毁,而此时可能还没来得及发出http请求,所以此次请求就会丢失。
解决:因此,我们使用闭包把img对象封闭起来,就可以解决数据丢失的问题:
var report = (function() {
var imgs = [];
return function(src) {
var img = new Image();
imgs.push(img);
img.src = src;
}
})()
(function(){
//i在外部就不认识啦
for(var i=0;i<count;i++){
}
})();
console.log(i);//报错,无法访问