首先我们来了解什么是闭包
闭包不是一个很具象的东西,这是一种机制,闭包让你可以在一个内层函数中访问到其外层函数的作用域。
闭包的作用
1.保护函数内的私有变量不受外界的干扰
2.形成不销毁的作用域可以把里面的变量保存下来
function fn() {
var arr = [];
for (var i = 0; i < 5; i++) {
arr[i] = function() {
return i;
}
}
return arr
}
let list = fn();
for (var i = 0; i < list.length; i++) {
console.log(list[i]());
}
什么情况会产生闭包?
1.函数内嵌套函数
2.内部函数引用了外层函数的变量
3.外部函数被调用
例:
function fn(i) {
return function(n) {
console.log(n + (++i));
}
}
let f = fn(6);//此时的f代表fn返回的内层函数
f(5); //这里的执行结果会在控制台打印12
fn(8)(10);//此时执行会产生新的私有上下文 所以此处会打印19
以下是解题思路
闭包的优点
1.延长了局部变量的生命周期
2.可以通过闭包实现一些更高级的功能
闭包的缺点
闭包会导致栈内存泄露,这里就要提一下堆栈内存的释放问题。
堆栈内存的释放问题
我们每次给变量存值或者执行函数的时候都会占用内存空间,如果一直这样下去,日积月累,电脑总会装不下的,所以内存
是需要释放的。
堆内存的释放:
常见的浏览器释放方式主要有以下两种:
谷歌浏览器是标记方式,每隔一段时间就会检测一下当前作用域中的内存,是否被占用,如果没有被占用,就会释放掉。
ie和火狐等浏览器是采用计数方法,当前作用域中如果一个空间地址被占用一次,就会累加一,如果减少一次占用就会减1
直到0的时候,说明已经没有被占用了,就释放了。
堆内存释放:让所有引用这个堆内存的变量赋值为null,堆内存地址不在被占用,浏览器在空闲的时候就会把堆内存释放
栈内存释放:
销毁:全局栈内存,只有当页面关闭的时候才会被释放
销毁:函数执行完成,一般情况下都会被销毁掉
总结
当我们执行函数的时候,会开辟栈内存和堆内存来执行代码,来存储一些数据。由于浏览器的垃圾回收机制导致一些情况下形成了不被及时释放的执行上下文,这样就形成了闭包。一方面保护了私有变量不被污染,另一方面也可以保存一些值,供它的下级上下文使用。在项目中我们也有很多时候会用到闭包,在ES6还没被大量应用之前,在做一些循环事件绑定的时候,会有索引的问题,我们就可以通过闭包来做,现在我们可以使用ES6的let来做,let内部已经帮我们实现了闭包,不需要再去自己写闭包,闭包的应用场景还包括防抖和节流等,在实际项目开发当中,我们要善用闭包,不要滥用闭包,毕竟会对内存造成一定的影响。