什么是闭包
在 js 中,有全局作用域和局部作用域,在局部作用域中可以访问全局作用域中的变量,反之则不行;在父级作用域中可以访问子级作用域中的变量,反之则不行。但有时,我们需要反向访问,该怎么办呢?这时,闭包应运而生。闭包,就是指能够访问其他函数内部变量的函数。
闭包的作用
- 读取其他函数内部的变量
- 让某些变量始终保持在内存中
例:
function f1(){
var n=999;
nAdd=function(){n+=1}
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
nAdd();
result(); // 1000
上述代码中,nAdd 函数虽是在f1 函数内部初始化,但没有加关键词var ,所以 nAdd 是一个全局函数,可在外部调用;
f1 函数的执行结果,return 一个函数 f2,f2 函数在f1 函数的内部定义,可读取f1 函数中的变量,所以 f2 函数是一个闭包;
var result = f1()
=>var result = f2 = function() { alert(n) }
,其中 n 是f1 的局部变量;
第一次执行 result()
时,直接打印出 n 的初始值 999;然后执行 nAdd() 函数,n 执行 +1 操作,n=1000;然后再次执行 result()
操作,此时打印出的 n 是 +1 后的值,1000;
此例说明,n 的值始终保持在内存中,没有被销毁。
闭包的缺点
- 由于闭包会让函数中的某些变量始终保持在内存中,所以不能大量使用,会很占用内存资源,造成网页卡顿崩溃;在IE中还可能导致内存泄漏
- 解决方法:可在退出函数之前将不使用的局部变量删除;delete 可删除对象的属性;普通变量将其置为 undefined 或 null 即可
- 闭包可以在 父函数的外部,改变其内部的值。如果将父函数当作对象使用,那其中的内部变量会有被修改的风险,具有一定的不稳定性
闭包的应用场景
- setTimeout、setInterval 中的回调函数
- ajax 中的回调函数
- 函数内部 return 一个匿名函数,这个匿名函数就是闭包
经典例题
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()()); // The Window
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()()); // My Object