什么是闭包,闭包造成的内存泄露如何解决

1、什么是闭包

闭包就是一个函数,能够访问其他函数内部变量的函数。
详细来说闭包就是在一个函数A内部定义一个新的函数B,并且这个新函数B,调用了在函数A内定义的变量,并且在函数A外部被调用,这就形成了闭包

2、闭包示例代码
function outer() {
     var  a = '变量1'
     var  inner = function () {
            console.info(a)
     }
     return inner    // inner 就是一个闭包函数,因为他能够访问到outer函数的作用域
}
var  inner = outer()   // 获得inner闭包函数
inner()   //"变量1"

当程序执行完var inner = outer(),其实outer的执行环境并没有被销毁,因为他里面的变量a仍然被inner函数作用域链所引用,当程序执行完inner(), 这时候,inner和outer的执行环境才会被销毁调;
闭包内存泄露的原因:《JavaScript高级编程》书中建议:由于闭包会将它的外部函数的作用域也保存在内存中,因此会比其他函数更占用内存,这样的话,如果过度使用闭包,就会有内存泄露的威胁

  • 基本类型变量(Number 、Boolean、Undefined、String、Null)的值一般都是存在栈内存中,
  • 引用类型变量(Array、Object、Function)的值存储在堆内存中,栈内存存储对应空间地址
3、闭包的优缺点

闭包的优点

  • 访问其他函数内部变量
  • 变量长期驻扎在内存中,不会被内存回收机制回收,即延长变量的生命周期
  • 避免定义全局变量所造成的污染

闭包的缺点
大量使用闭包,造成内存占用空间增大,有内存泄露的风险

4、如何避免闭包引起的内存泄漏

1,在退出函数之前,将不使用的局部变量赋值为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;                                          // 将闭包引用的外部函数中活动对象清除
    }

2,避免变量的循环赋值和引用。 (示例如上)

循环引用引起的内存泄漏,是因为IE 的bug,循环引用无法自动判断,所以通过拷贝值,把内外引用脱钩,这样就可回收。IE9及其以后已修复。(感谢 猫SirSir 的讲解!)

3,利用Jquery释放自身指定的所有事件处理程序。
由于jQuery考虑到了内存泄漏的潜在危害,所以它会手动释放自己指定的所有事件处理程序。 只要坚持使用jQuery的事件绑定方法,就可以一定程度上避免这种特定的常见原因导致的内存泄漏。

这段代码会导致内存泄露
$(document).ready(function() {
    var button = document.getElementById('button-1');
    button.onclick = function() {
         console.log('hello');
         return false;
    };
});
当指定单击事件处理程序时,就创建了一个在其封闭的环境中包含button变量的闭包。而且,现在的button也包含一个指向闭包(onclick属性自身)的引用。这样,就导致了在IE中即使离开当前页面也不会释放这个循环。

用jQuery化解引用循环
$(document).ready(function() {
    var $button = $('#button-1');
    $button.click(function(event) {
        event.preventDefault();
        console.log('hello');
    });
});
5、闭包常见的应用场景
1、柯里化函数

为了避免频繁地调用具有相同参数的函数,可以将一个多参数的函数转化为一个单参数的函数,
其实就是一个高阶函数

//普通函数
function getArea(w,h){
    return w * h;
}
const area1 = getArea(10,20);
const area2 = getArea(10,30);
const area3 = getArea(10,40);

//柯里化函数
function getArea(w){
    return function(h){
        return w * h;
    }
}
const getTenArea = getArea(10);

const area1 = getTenArea(20);
const area2 = getTenArea(30);
const area3 = getTenArea(40);

2、通过闭包实现变量/方法的私有化
function funOne(i){
    function getTwo(){
        console.log('参数:', i)
    }
    return getTwo;
}
const fa = funOne(100); 
const fb = funOne(200); 
const fc = funOne(300); 

3、匿名自执行函数
var funOne = (function(){
    var num = 0;
    return function(){
        num++;
        return num;
    }
})()

console.log(funOne());   // 1
console.log(funOne());   // 2
console.log(funOne());   // 3 

4、缓存一些结果

比如:外部函数定义一个变量,内部函数可以获取或修改这个变量的值,从而就延长了这个变量的生命周期

function parent(){
    let list = [];
    function son(i){
        list.push(i);
    }
    return son;
}

const fn = parent();

fn(1);
fn(2);
fn(3);

参考链接: https://blog.youkuaiyun.com/liuzijiang1123/article/details/81226797
参考链接:https://www.cnblogs.com/yakun/p/3932026.html
参考链接:https://www.jianshu.com/p/26c81fde22fb

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值