5.①闭包优(延长生命周期)缺点②闭包作用域③闭包应用:节流和防抖要注意this和arguments④闭包面试题

本文深入探讨了JavaScript中的闭包,包括它的三大要素、优点、缺点、生命周期以及如何解决内存问题。闭包在函数作用域、缓存、防抖和节流等方面有广泛应用,如在缓存示例中,通过闭包实现变量持久化。同时,文章还提供了多个闭包面试题以加深理解。
摘要由CSDN通过智能技术生成

目录

一:闭包的三大要素:

    1.函数存在嵌套关系

    2.内部函数必须引用外部函数的局部变量

    3.外部函数必须调用

 二:闭包优点:

   1.能够在函数外部 访问到内部的变量(原本函数外部无法访问函数内部的局部变量,但函数内部的函数可以访问本函数内的局部变量)

   2.延长局部变量的生命周期(本质:)

    var fnn2 = fn() 本来执行一次内部变量a就应该销毁,但是因为被赋值了有引用关系,局部变量就一直保存

三: 闭包的缺点

   1.滥用闭包,其执行环境一直都在 造成内存溢出 和内存泄漏

四:闭包的生命周期

   1.产生:闭包在完成嵌套函数(成立的三大要素)时就产生了(而不是调用)

   2.死亡:接收闭包的变量称为垃圾对象时 (null)

五:闭包缺点的解决

    1.内存泄漏:内存无法释放

    2.内存溢出:内存被撑爆

    3.解决:f=null ;让闭包机制清除,f指接收外部函数的那个变量

六:闭包作用域:在函数被创建的地方开始向上寻找

1.函数作为返回值被返回

2.函数作为参数被传递

七:闭包的应用场景

1.做缓存

2.防抖或是节流:限制函数的执行次数

3.节流throttle:减少一段时间的触发频率(规定多久以后才能触发一次)

①定时器版本

②时间戳版本:

4.防抖debounce:通过setTimeout的方式,在一的时间间隔内,将多次触发变成一次触发,执行最后一次

注意this指向和参数arguments问题

八:闭包面试题

1.不是闭包

2.是闭包

3.是闭包(难)


一:闭包的三大要素:

    1.函数存在嵌套关系

    2.内部函数必须引用外部函数的局部变量

    3.外部函数必须调用

 二:闭包优点:

   1.能够在函数外部 访问到内部的变量(原本函数外部无法访问函数内部的局部变量,但函数内部的函数可以访问本函数内的局部变量)

   2.延长局部变量的生命周期(本质:)

    var fnn2 = fn() 本来执行一次内部变量a就应该销毁,但是因为被赋值了有引用关系,局部变量就一直保存

三: 闭包的缺点

   1.滥用闭包,其执行环境一直都在 造成内存溢出 和内存泄漏

四:闭包的生命周期

   1.产生:闭包在完成嵌套函数(成立的三大要素)时就产生了(而不是调用)

   2.死亡:接收闭包的变量称为垃圾对象时 (null)

五:闭包缺点的解决

    1.内存泄漏:内存无法释放

    2.内存溢出:内存被撑爆

    3.解决:f=null ;让闭包机制清除,f指接收外部函数的那个变量

六:闭包作用域:在函数被创建的地方开始向上寻找

1.函数作为返回值被返回

2.函数作为参数被传递

七:闭包的应用场景

1.做缓存

  <script>
    function mycache(){
      let cache = {}
      return {
        setN:function(key,value){
          cache[key] = value
        },
        getN:function(key){
          return cache[key]
        }
      }
    }
    let a = mycache()
    a.setN(1,'嘿嘿嘿')
    console.log(a.getN(1))         //嘿嘿嘿

    // 以下不会正常输出(因为调用了两次 内存中生成了两次cache变量 两次操作的不是同一个)
    mycache().setN(2,'嘿嘿嘿')
    console.log(mycache().getN(2)) //undefined
  </script>

2.节流,防抖:限制函数的执行次数

3.节流throttle:减少一段时间的触发频率(规定多久以后才能触发一次)

①定时器版本

<body>
    <button id="btn">节流定时器版本</button>
    <script>
        let btn = document.getElementById('btn')
        function fn(arguments){
            console.log(this.innerHTML);  //节流定时器版本
            console.log(arguments)  // PointerEvent {isTrusted: true, pointerId: 1, ...}
        }
        let delay = 3000
        btn.addEventListener('click',throttle(fn,delay))
        function throttle(fn,delay){
            let timer = true   //时间已到
            return function(){
                if(timer){
                  setTimeout(()=>{
                     fn.apply(this,arguments)
                     timer = true //异步三秒后变为true,可再次点击按钮执行fn
                  },delay)
                }
                timer = false    //立即为false
            }
        }
    </script>
</body>

②时间戳版本:

<body>
    <button id="a">节流时间戳版本</button>
    <script>
      let a =  document.getElementById('a')
      function fn(arguments){
          console.log(this.innerHTML)
          console.log(arguments);
      }
      
      let delay = 3000
      a.addEventListener('click',throttle(fn,delay))
  
      function throttle(fn,delay){
          let time = 0
          return function(){
              let newtime = new Date().getTime()
              if(newtime - time > delay ){
                  fn.apply(this,arguments)
                  time = newtime
              }
          }
      }
    </script>
  </body>

4.防抖debounce:通过setTimeout的方式,在一的时间间隔内,将多次触发变成一次触发,只执行最后一次

注意this指向参数arguments问题

<body>
  纠正this指向及event对象!
  <button id="btn">防抖</button>
  <script>
    let btn = document.getElementById('btn')

    let delay = 1000 //延迟时间

    // 参数:输出e:触发的鼠标点击事件相关信息,接收arguments
    function fn(e){ 
      console.log(this.innerHTML)   //防抖
      console.log(e) //PointerEvent {isTrusted: true, pointerId: 1, width: 1, …}
    }

    btn.addEventListener('click',debounce(fn,delay))

    function debounce(fn,delay){
      let timer = null; 
      return function(){
        // 下一个定时器运行时,清除上一个定时器
        if(timer) clearTimeout(timer)  //null为false,timer有值才为true
        //this:用箭头函数写,this可以指向btn,否则是window
        timer = setTimeout(()=>{  
        //this:修改fn()方法的this指向     
          fn.apply(this,arguments)    //参数:传递arguments,不传是undefined
          console.log(this)           //<button id="btn">防抖</button>
          },delay)
      }
    }
  </script>
</body>

八:闭包面试题

1.不是闭包

The Window

2.是闭包

My Object

3.是闭包(难)


        function fun(n, o) {

            console.log(o)
            return {
                fun: function (m) {
                    return fun(m, n)
                }
            }
        }
        var a = fun(0);
        // 将0传入n中 n=0 o没传值, 所以 console.log(0)为undefined
        //1. 此时 a是一个对象fun函数的返回值
        // console.log(typeof a)   //object
        /*    var a = {
                 fun: function (m) {
                      return fun(m, n)
                  }
          } */
        //2. a.fun是匿名函数 f (m){   return fun(m, n) }
        // console.log(typeof a.fun)  //function

        a.fun(1);  //f (1){   return fun(1, n) }   n去外层找 n=最开始传入的0
        //  根据返回的公式 去找有名函数fun并传入参数n=1  ,o=0   输出console.log(0)为0

        a.fun(2);  //f (2){   return fun(2, n) }   n去外层找 n=最开始传入的0
        //  根据返回的公式 去找有名函数fun并传入参数n=2  ,o=0   输出console.log(0)为0

        a.fun(3); //f (3){   return fun(3, n) }   n去外层找 n=最开始传入的0
        //  根据返回的公式 去找有名函数fun并传入参数n=3  ,o=0   输出console.log(0)为0


        var b = fun(0).fun(1).fun(2).fun(3);

        //1.  var b = fun(0)
        /*        var b = {
                    fun : fun(m){
                       return fun(m,0)
                    }
                 }
        
       输出:  n = 0 o = undefined */

        //2.  var b = fun(0).fun(1)相当于 
        /*        var b = {
                    fun:function(1){
                        return fun(1,n)   //n是之前的0 return fun(1,0)
                    }
                }
         
        输出:  n = 1 o =0 */

        //3.  var b = fun(0).fun(1).fun(2)相当于
        /*         var b = {
                    fun:function(2){
                        return fun(2,n)  //n是之前的 1
                    }
                }
         
        输出:  n = 2  o = 1 */

        //4.  var b = fun(0).fun(1).fun(2).fun(3)相当于
        /*         var b = {
                    fun:function(3){
                        return fun(3,n)  //n是之前的 2
                    }
                }
         
        输出:  n = 3  o = 2 */

        var c = fun(0).fun(1);
        /*    var c = fun(0)   n=0 o=undefined 先输出一个undefined  
          相当于一个对象,内部有属性为匿名函数,传入参数m
            var c = fun(0).fun(1); 相当于 给匿名函数传参为 1
            此时 m = 1 n = 0  
        */
        c.fun(2);//就是调用return里面属性的匿名函数
        // 传入m = 2
        // m=2 n=1
        c.fun(3);
        // 传入m = 3
        // m = 3  n= 1

  • 11
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值