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

Posted 宁静致远

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重点突破——如何快速识别并解决“闭包问题”?相关的知识,希望对你有一定的参考价值。

一、引言

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

 

二、闭包

  • 什么是? 一种对象,向外公开了特定的数据,以及操作这种数据的方法,供外部调用,就是闭包
  • 为什么?  
  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为实参
}

 

 


 注:转载请注明出处

以上是关于重点突破——如何快速识别并解决“闭包问题”?的主要内容,如果未能解决你的问题,请参考以下文章

重点突破—— Nodejs+Express+MongoDB的使用基础

怎样在word中快速输入复杂的公式(数学、物理或化学公式)?

王晓刚深度学习在图像识别中的研究进展与展望

重点突破—— Easy Mock的使用及Mock.js规范

超硬核:优驾实现车载图像识别技术突破并测试成功!

如何让程序更快的运行