【闭包篇】闭包其实很简单

344 阅读2分钟

什么是闭包?

闭包就是在函数内部定义函数,并且内部函数会引用函数的变量,实现局部变量的应用,防止全局变量的污染

闭包的优缺点

优点

它可以实现局部变量的定义,防止全局变量的污染

缺点

它会造成不使用的内存不会被主动回收,造成内存泄露,需要人为手动进行清除,清除的方式就是将值赋予null,清除内存引用。

补充知识点 内存泄露:指的是不再被使用的内存空间没有被得到释放,占用内存空间。

基础闭包案例图解

image.png

1.第1-7行,定义了一个funcA函数,这个函数属于全局函数,内存空间存放再堆中(跟闭包知识点无关)。

2.第8行,使用useFuncA接收funcA函数return出来的funcB函数,在执行funcA时,创建了两个内存空间,一个内存空间存放return出来的funcB,一个在执行funcA时创建的内存空间存放了funcA定义的变量。

如果是普通函数的话,funcA创建的内存空间在执行完就会被进行垃圾回收,由于return回去的funcBfuncA创建的空间变量进行了引用,造成该内存空间被标记为被属于被引用的内存,所以不会被垃圾回收。

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被多个事件公用,造成变量污染,无法针对单个按钮事件进行一个防抖操作。