什么是闭包
简单来说,闭包是指可以访问另一个函数作用域变量的函数,一般是定义在外层函数中的内层函数。
为什么需要闭包呢
局部变量无法共享和长久的保存,而全局变量可能造成变量污染,所以我们希望有一种机制既可以长久的保存变量又不会造成全局污染。
实现代码:
<script>
let count = 500 //全局作用域
function foo1() {
let count = 0;//函数全局作用域
function foo2() {
count++;//函数内部作用域
console.log(count);
return count;
}
return foo2;//返回函数
}
let result = foo1();
result();//结果为1
result();//结果为2
result();//结果为3
</script>
首先foo1()返回的是一个foo2()函数,当我们调用result()的时候就会返回foo2()执行的函数,foo2()里面有什么呢? 首先我们看到如下有一个count变量,但是没有定义.我们根据JavaScript的作用域链的定义可知,当函数内部的变量没有定义的时候,就会采用冒泡的方式,向上一级寻找.上一级没有接着上一级找,直到最顶层window. 如果都没有,就会报undefined的错误.这里我们在foo1()中找到了count,于是count+1,第一次输出的是1,没有什么问题.
但是第二次我们再执行result()的时候就出现了问题,为什么会是2呢?按照流程,首先再foo2()函数内部寻找count,没有然后到外层寻找,找到了count=0,这时候count+1应该为1才对.这里就涉及到闭包的问题了.
闭包的应用场景
- 防抖
- 节流
- 详细代码请看防抖与节流https://blog.youkuaiyun.com/qq_45952585/article/details/124069356?spm=1001.2014.3001.5501
- setTimeout
- 封装私有变量
- 等等
原生的setTimeout传递的第一个函数不能带参数,通过闭包可以实现传参效果。
function f1(a) {
function f2() {
console.log(a);
}
return f2;
}
var fun = f1(1);
setTimeout(fun, 1000); //一秒之后打印出1
闭包的缺点和解决方法
缺点:闭包会保存函数中的变量在内存中,不会被垃圾回收机制回收,导致内存消耗大,可能会造成内存泄漏
解决方法:
// 这段代码会导致内存泄露
function test() {
var a = document.getElementById("id");
a.onclick = function () {
alert(a.id);
}
}
// 解决方法为
function test1() {
var a = document.getElementById("id");
var id = a.id; //解除循环引用
a.onclick = function () {
alert(id);
}
a = null; // 将闭包引用的外部函数中活动对象清除
}