深入解析JS闭包

260 阅读2分钟

什么是闭包

闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。

function f1(){
    var a = 9;
    function f2(){
        return a
    }
    return f2;
}

var result = f1()
let a = result()  // a=9

闭包的应用场景

一、setTimeout函数传参

setTimeout(fn,delay)函数的第一个参数为函数fn,fn是不允许传入参数的。但是合理地使用闭包,也可以达到函数传参的目的。比如:

function f3(a){
    return function f4(){
       console.log(a)
    }
}
var fn = f3(5)
setTimeout(fn,5000)  //5秒后打印数字5

二、函数回调自定义行为

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>闭包</title>
</head>
<body>
    <a href="#" id="size-16">16</a>
    <a href="#" id="size-25">25</a>
    <a href="#" id="size-60">60</a>
    <script type="text/javascript">
        function changeSize(size){
            return function(){
                document.body.style.fontSize = size + 'px';
            };
        }
        var size16 = changeSize(16);
        var size25 = changeSize(25);
        var size60 = changeSize(60);
        document.getElementById('size-16').onclick = size16;
        document.getElementById('size-25').onclick = size15;
        document.getElementById('size-60').onclick = size60;
    </script>
</body>

</html>

三、函数防抖

在实际的业务场景中,为了防止一个事件连续重复的不断发生,常常需要使用函数防抖。在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。实现的关键就在于setTimeOut这个函数,由于还需要一个变量来保存计时。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>函数防抖</title>
</head>
<body>
    <a href="#" id="debounce">函数防抖</a>

    <script type="text/javascript">
        document.getElementById('debounce').onclick = debounce(fn1,5000);

        // 函数防抖
        function debounce(fn,delay) {
            let timer = null
            return function(){
                if(timer) {
                    clearTimeout(timer);
                    timer = setTimeout(fn,delay)
                } else {
                    timer = setTimeout(fn,delay)
                }
            }
        }

        function fn1(){
            console.log(5);
        }

    </script>
</body>
</html>

四、封装私有变量

下面通过闭包的形式封装一个私有变量,来实现js计数器的功能。

function r1(){
   let sum = 0;
   let obj = function(){
         sum++;
         console.log(sum);
         return sum;
   }
   return obj
}

let result = r1();
result(); // 1
result(); // 2
result(); // 3

使用闭包要注意的问题

由于在闭包所在的作用域返回的局部变量不会被销毁,所以会占用内存。过度的使用闭包会迫使性能下降,因此建议大家在有必要的情况下再使用闭包。