• 【重点突破】——如何快速识别并解决“闭包问题”?


    一、引言

    什么是“闭包”?它既是前端程序中常常会碰到的一个千年大坑,也是这个大坑唯一可以解决自身的办法。很多大牛对闭包都有自己的解释,但每个人的解释可能都不太一样,看太多反而混乱,这里,我会用一个小例子,尽量简单的说明这个“闭包”到底是什么,怎么识别?如何解决?

    二、闭包

    • 什么是? 一种对象,向外公开了特定的数据,以及操作这种数据的方法,供外部调用,就是闭包
    • 为什么?  
    1. 全局变量:随处可见,可反复使用。缺点:极易被污染(易被篡改)。
    2. 局部变量:不会被污染。缺点:仅函数内可用,且不可重用(不易被篡改)。
    • 三大特点
    1. 外层函数
    2. 受保护的变量
    3. 内层函数

    三、如何形成闭包

          外层函数的作用域对象无法释放,导致:外层函数的局部变量被保存下来(可以重用)。

    • 第一步:将受保护的变量和操作变量的函数封装在一个外层函数;
    • 第二步:外层函数,要将内层函数队形返回;
    • 第三步:使用者调用外层函数,获得内层函数对象。

    四、快速识别

    • 向外抛出对象,一定是闭包。
    • 模型:循环函数嵌套一个内层函数对象返回变量值,外部调用此函数对象,得不到不同变量值的,一定是闭包问题。(依据闭包问题的原因,最后得到的值一定都是内层循环函数获得的最后一个变量值) 。

    五、例题说明

    点击1,2,3按钮,获得对应按钮值,有如下代码:

    <body>
        <h3>JS中的闭包陷阱</h3>
        <button>1</button>
        <button>2</button>
        <button>3</button>
        <script>
           var list = document.querySelectorAll('button');
           for(var i=0;i<list.length;i++){
               var b = list[i];
               b.onclick = function(){
                   console.log(i);
               }
           };
        </script>
     </body>

    打印结果:

    坑:这属于典型的闭包问题,打不出0,1来,全部为3。

    原因:变量i就1个,并且这段代码不仅是对外公开了一个变量i,还公开了三个不同的监听函数,分别绑定给不同的按钮。

    如果看所有JS调用完成(函数外打印),i的值,如下:

    console.log('JS调用完成,i='+i);

    结果:

    所以:此时所有JS都已调用完成,i的值等于3。但是,按钮的事件监听并没有调用,可它们都要用i,因此,这个时候,再手动调用事件监听,所获得的i值只能是3。

    六、解决方法

    闭包问题必须要靠闭包方案来解决

    1. 把原本的一个闭包,拆分成三个闭包(复杂)
    2. 匿名函数,转化为有名函数(简单)
    //方法一:把原本的一个闭包拆为三个
    for(var i=0;i<list.length;i++){
        var b = list[i];
        b.onclick = outer(i);
    }
    
    function outer(num){
        function inner(){
           console.log(num);
        }
        return inner;
    }
     //方法二:匿名函数变成有名函数
    for(var i=0;i<list.length;i++){
         var b = list[i];
         b.onclick = (function(num){//外部函数--此处传递形参num,注意不能再取i为变量名,否则又会重复
            return function(){//内部函数
            console.log(num);
                }
         })(i);//闭包上下文变量i,实参
    }

    结果:

    如果打印btn,实现代码和效果如下:

    for(var i=0;i<list.length;i++){
         var b = list[i];
         b.onclick = (function(btn){//外部函数-
            return function(){//内部函数
            console.log(btn);
                }
         })(b);//传递b为实参
    }

     注:转载请注明出处

  • 相关阅读:
    BZOJ1033:[ZJOI2008]杀蚂蚁antbuster(模拟)
    BZOJ4001:[TJOI2015]概率论(卡特兰数,概率期望)
    BZOJ1820:[JSOI2010]Express Service 快递服务(DP)
    BZOJ4066:简单题(K-D Tree)
    2110. [NOIP2015普及]金币
    73. 找最佳通路
    cogs 7. 通信线路
    codevs 3295 落单的数
    151. [USACO Dec07] 建造路径
    必备算法之二叉树的相关操作
  • 原文地址:https://www.cnblogs.com/ljq66/p/7668681.html
Copyright © 2020-2023  润新知