什么是闭包?
闭包就是在函数内部定义函数,并且内部函数会引用函数的变量,实现局部变量的应用,防止全局变量的污染
闭包的优缺点
优点
它可以实现局部变量的定义,防止全局变量的污染
缺点
它会造成不使用的内存不会被主动回收,造成内存泄露,需要人为手动进行清除,清除的方式就是将值赋予null,清除内存引用。
补充知识点 内存泄露:指的是不再被使用的内存空间没有被得到释放,占用内存空间。
基础闭包案例图解
1.第1-7行,定义了一个funcA函数,这个函数属于全局函数,内存空间存放再堆中(跟闭包知识点无关)。
2.第8行,使用useFuncA接收funcA函数return出来的funcB函数,在执行funcA时,创建了两个内存空间,一个内存空间存放return出来的funcB,一个在执行funcA时创建的内存空间存放了funcA定义的变量。
如果是普通函数的话,funcA创建的内存空间在执行完就会被进行垃圾回收,由于return回去的funcB对funcA创建的空间变量进行了引用,造成该内存空间被标记为被属于被引用的内存,所以不会被垃圾回收。
3.第9-10行,执行funcB函数。
4.第11行,清除对funcB的引用,此时,funB与funcA使用时创建的内存将会被进行系统回收。(如果在用完该功能没有主动设置为null的话,该内存就会一直被标记为引用中,无法释放,造成内存泄漏)
引用闭包的经典案例(防抖)
function debounce(ajax,delay) {
let setTimeoutId
return function(...args) {
clearTimeout(setTimeoutId)
setTimeoutId = setTimeout(() => {
ajax.apply(this,args)
}, delay);
}
}
let useDebounce = debounce(function () {
console.log(1)
}, 1000)
document.getElementById('id').onclick = useDebounce
引用闭包的经典案例(节流)
function throttle(ajax,delay) {
let lastTime = 0;
return function(...args) {
let nowTime = Date.now()
if(nowTime - lastTime < delay) {
lastTime = nowTime
ajax.apply(this,args)
}
}
}
let newThrottle = throttle(function () {
console.log(1)
}, 1000)
document.getElementById('id').onclick = newThrottle
不用闭包实现的(防抖)
let setTimeoutId
function debounce(ajax,delay) {
clearTimeout(setTimeoutId)
setTimeoutId = setTimeout(() => {
ajax.call()
}, delay);
}
let useDebounce = debounce(function () {
console.log(1)
}, 1000)
let useDebounce2 = debounce(function () {
console.log(2)
}, 1000)
document.getElementById('id').onclick = useDebounce
document.getElementById('id2').onclick = useDebounce2
此时存在setTimeoutId被多个事件公用,造成变量污染,无法针对单个按钮事件进行一个防抖操作。