闭包

什么是闭包?

我的理解是,闭包就是函数嵌套函数,内部函数能够读取其他函数内部变量的函数。

由于在Javascript语言中,只有函数内部的函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。

所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

闭包的用途

闭包可以用在许多地方。它的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

闭包的特性

1、函数嵌套函数

2、内部函数可以直接访问外部函数的内部变量或参数

3、变量或参数不会被垃圾回收机制回收

闭包的优点:

1、变量长期驻扎在内存中

2、避免全局变量的污染

3、私有成员的存在

闭包的缺点:

  1. 不能及时释放内存
  2. 对捕获的变量是引用,不是复制
  3. 父函数每调用一次,会产生不同的闭包

什么是内存泄漏

首先,需要了解浏览器自身的内存回收机制。
每个浏览器会有自己的一套回收机制,当分配出去的内存不使用的时候便会回收;内存泄露的根本原因就是你的代码中分配了一些‘顽固的’内存,浏览器无法进行回收,如果这些’顽固的’内存还在一直不停地分配就会导致后面所用内存不足,造成泄露。

造成内存泄露的原因:

1、意外的全局变量(在函数内部没有使用var进行声明的变量)

2、console.log

3、闭包

4、对象的循环引用

5、未清除的计时器

6、DOM泄露(获取到DOM节点之后,将DOM节点删除,但是没有手动释放变量,拿对应的DOM节点在变量中还可以访问到,就会造成泄露)


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

1、在退出函数之前,将不使用的局部变量全部删除,可以使变量赋值为null

//这段代码会导致内存泄露
    window.onload = function(){
        var el = document.getElementById("id");
        el.onclick = function(){
            console.log(el.id);
        }
    }

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

2、避免变量的循环赋值和引用 

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

//这段代码会导致内存泄露
$(document).ready(function() {
    var app = document.getElementById('#app');
    app.onclick = function() {
         console.log('hello world');
         return false;
    };
});

//当指定单击事件处理程序时,就创建了一个在其封闭的环境中包含app变量的闭包。而且,现在的app也包含一个指向闭包(onclick属性自身)的引用。这样,就导致了在IE中即使离开当前页面也不会释放这个循环。

//用jQuery化解引用循环
$(document).ready(function() {
    var $app= $('#app');
    $app.click(function(event) {
        event.preventDefault();
        console.log('hello !!!小明');
    });
});

//注:$(document).ready()所要执行的代码是在DOM元素被加载完成的情况下执行
//window.onload = function(){ console.log("welcome to beijing"); }语句的作用是希望在页面加载完,自动执行定义js代码(function)
在页面中$(document).ready(function(){.... })这个函数是用来取代页面中的window.onload;

闭包的使用场景

1、setTimeout的使用

<script>
    
//原生的setTimeout传递的第一个函数不能带参数,通过闭包可以实现传参数
function fun(a){

    function fun2(){
        console.log(a);
        }
       return fun2;
    }

    var fn=fun(1);
    setTimeout(fn,1000);//一秒之后打印出1;
</script>

2、回调

3、封装私有变量

<script>

    //再返回的对象中,实现了一个闭包,该闭包携带了几步变量sum,并且,从外部代码根本无法访问到变量
      
    function fun(){
    var sum=0;
    var obj={
        say:function(){
            sum++;
            return sum;
        }
    }
        return obj;
}

   let result=fun();
    console.log(result.say());//打印结果为1;
    console.log(result.say());//打印结果为2;



    function fn(){
        var sum=0;
        function fn2(){
        sum++;
        return fn2;
    }
    fn2.valueOf=function(){
        return sum;
    }
    fn2.toString=function(){
        return sum+'';
    }
    return fn2;
}
//执行fn函数,返回的是fn2函数
console.log(+fn());//打印结果0;
console.log(+fn()());//打印结果1;
</script>

4、函数防抖节流

函数防抖:

<script>
    //函数防抖是指在函数被高频触发时当停止触发后延时n秒在执行的函数(即每次触发都清理延时函数再开始计时),一般用于resize,scroll,mousemove等
function fun(a){
    let timeout=null;//通过闭包创建一个标记用来存放定时器的返回值
    return function(){
        clearTimeout(timeout);//每当用户输入的时候把前一个setTimeout清空掉
        timeout=setTimeout(()=>{//然后又创建一个新的setTimeout,这样就能保证输入字符后interval间隔内如果还有字符输入的话,就不会执行a函数
            a.apply(this.arguments);
        },500);
    }
}
function say(){
    console.log('防抖成功')
}
var app=document.getElementById('app');
app.addEventListener('input',debounce(say));//防抖
</script>

函数节流:

<script>
    //函数节流:原理 函数被高频触发时延迟n秒后才会再次执行。
    //防抖主要是用户触发最后一次事件后,延迟一段时间触发,而节流会规定的
    function fun(fn,delay){
    let timer=null;
    let startTime=Date.now();
    return function(){
        let curTime=Date.now();
        let remaining=delay-(curTime-startTime);
        const args=arguments;
        clearTimeout(timer);
        if(remaining<=0){
            fn.apply(this.args);
            startTime=Date.now();
        }else{
            timer=setTimeout(fn,remaining);
        }
    }
}
function show(){
    console.log('111');
}
document.addEventListener('click',throttle(show,2000));


//注:Date.now() 方法返回自 1970 年 1 月 1 日 00:00:00 (UTC) 到当前时间的毫秒数。
</script>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值