闭包是什么?

289 阅读4分钟

闭包是什么?

    闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取[局部变量],所以
闭包可以理解成“定义在一个[函数]内部的函数”。 在本质上,闭包是将函数内部和函数外部连接起来的桥梁
    通俗一点说就是可以在函数外部访问到函数内部的变量,因为正常情况下函数外部是访问不到函数内部作用域变量的。

作用域分为什么?

作用域分为了,全局变量,函数变量和块级作用域

闭包的优点

    可以重复使用变量并且不会造成变量污染,可以隔离作用域,不会全局污染
    闭包结合了全局变量和局部变量的优点,可以用来定义私有属性和私有方法
    全局变量可以重复使用,但是容易造成变量污染,局部变量仅在局部作用域内有效,不可以重复使用,不会造成变量
 污染

闭包的缺点

    比普通函数更占内存,会导致网页性能变差,在IE下容易造成内存泄漏,由于闭包长期驻留内存,则会导致内存泄漏

什么是内存泄漏

    因为闭包就是能够访问外部函数变量的一个函数,而函数是必须保存在内存中的对象,所以位于函数执行上下文中的所
有变量也需要保存在内存中,这样就不会被回收,如果一旦循环引用或创建闭包,就会占据大量内存,可能会引起内存泄漏

如何避免内存泄露?

    在退出函数之前,将不使用的局部变量全部删除 我们可以将暴露在外部的闭包变量置为null
//这段代码会导致内存泄露
    window.onload = function(){
        var el = document.getElementById("id");
        el.onclick = function(){
            alert(el.id);
        }
    }

    //解决方法为
    window.onload = function(){
        var el = document.getElementById("id");
        var id = el.id; //解除循环引用
        el.onclick = function(){
            alert(id); 
        }
        el = null; // 将闭包引用的外部函数中活动对象清除
    }

怎么判断是不是闭包?

    函数嵌套函数,内部函数被return,内部函数调用外部函数的局部变量
    function a(){
        var i=0;

        function b(){
        alert(++i);
        }
        return b;
    }var c=a();
    c();
    简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制不会收回a所占用的资源,因为a
的内部函数b的执行需要依赖a中的变量

闭包的适用场景

    封装功能时(需要使用私有的属性和方法),函数防抖、函数节流、函数柯里化、给元素伪数组添加事件需要使用元素的
索引值,使用防抖节流函数就是闭包的原理,导航栏获取下标使用
/**
 * @function throttle 函数节流
 * @param {Function} fn 需要节流的函数
 * @param {Number} interval 间隔时间
 * @return {Function} 经过节流处理的函数
 * */
function throttle(fn, interval) {
    let timer = null; // 定时器
    let firstTime = true; // 判断是否是第一次执行
    // 利用闭包
    return function() {
        // 拿到函数的参数数组
        let args = Array.prototype.slice.call(arguments, 0);
        // 拿到当前的函数作用域
        let _this = this;
        // 如果是第一次执行的话,需要立即执行该函数
        if(firstTime) {
            // 通过apply,绑定当前函数的作用域以及传递参数
            fn.apply(_this, args);
            // 修改标识为null,释放内存
            firstTime = null;
        }
        // 如果当前有正在等待执行的函数则直接返回
        if(timer) return;
        // 开启一个倒计时定时器
        timer = setTimeout(function() {
            // 通过apply,绑定当前函数的作用域以及传递参数
            fn.apply(_this, args);
            // 清除之前的定时器
            timer = null;
            // 默认300ms执行一次
        }, interval || 300)
    }
}
限制一个函数在一定时间内只能执行一次。

小结

    由于闭包会使得函数中的[变量]都被保存在内存中,[内存]消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,
在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。