JS中for循环里面的闭包问题的原因及解决办法

简介: 我们先看一个正常的for循环,普通函数里面有一个for循环,for循环结束后最终返回结果数组function box(){    var arr = [];    for(var i=0;i

我们先看一个正常的for循环,普通函数里面有一个for循环,for循环结束后最终返回结果数组

function box(){

    var arr = [];

    for(var i=0;i<5;i++){

        arr[i] = i;       

    }

    return arr;

}

alert(box())   

//正常情况不需要闭包,就可以达到预期效果,输出结果为一个数组0,1,2,3,4

 

 

有时我们需要在for循环里面添加一个匿名函数来实现更多功能,看下面代码

//循环里面包含闭包函数

function box(){

    var arr = [];

    for(var i=0;i<5;i++){

        arr[i] = function(){

            return i;         //由于这个闭包的关系,他是循环完毕之后才返回,最终结果是4++是5

        }                    //这个匿名函数里面根本没有i这个变量,所以匿名函数会从父级函数中去找i,

    }                      //当找到这个i的时候,for循环已经循环完毕了,所以最终会返回5

    return arr;

}

//alert(box());        //执行5次匿名函数本身

//alert(box()[1]);   //执行第2个匿名函数本身

//alert(box().length);   //最终返回的是一个数组,数组的长度为5

alert(box()[0]());    //数组中的第一个数返回的是5,这是为什么?

 

上面这段代码就形成了一个闭包:

闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的常见的方式,就是在一个函数内部创建另一个函数,通过另一个函数访问这个函数的局部变量。

在for循环里面的匿名函数执行 return i 语句的时候,由于匿名函数里面没有i这个变量,所以这个i他要从父级函数中寻找i,而父级函数中的i在for循环中,当找到这个i的时候,是for循环完毕的i,也就是5,所以这个box得到的是一个数组[5,5,5,5,5]。

 

解决方案

在看解决方案一之前,我们先看一下匿名函数的自我执行:

匿名函数自我执行的写法是,在函数体外面加一对圆括号,形成一个表达式,在圆括号后面再加一个圆括号,里面可传入参数。

例如下代码:

(function(){

    alert('lee');     //匿名函数自我执行(匿名函数)()

})();

 

解决方案1:

function box(){

    var arr = [];

    for(var i=0;i<5;i++){

        arr[i] = (function(num){        //自我执行,并传参(将匿名函数形成一个表达式)(传递一个参数)

          return num;        //这里的num写什么都可以                   

      })(i);        //这时候这个括号里面的i和上面arr[i]的值是一样的都是取自for循环里面的i                           

    }                                           

    return arr;

}

//alert(box());                               

//alert(box()[1]);

//alert(box().length);                           

alert(box()[0]);       

 

解决方案2

这种方案的原理就是在匿名函数1里面再写入一个匿名函数2,这个匿名函数2需要的num值会在他的父级函数匿名函数1里面去寻找,而匿名函数1里面的num值就是传入的这个参数i,和上面例子中的i是一样的,

function box(){

    var arr = [];

    for(var i=0;i<5;i++){

        arr[i] = (function(num){

        //num在这里             //原理和上面一种方法一样的,所以可以实现闭包                   

        return function(){      //在这个闭包里面再写一个匿名函数

                return num;                           

            };                                                                

        })(i)                                               

    }

    return arr;

}

//alert(box());                               

//alert(box()[1]);

//alert(box().length);

var b = box();                           

alert(b[0]());

alert(box()[0]());

box()最终返回结果[0,1,2,3,4],

 

案例详解

<html >  

<head>  

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  

<title>闭包演示</title>  

<script type="text/javascript">  

function init() {  

  var pAry = document.getElementsByTagName("p");  

  for( var i=0; i<pAry.length; i++ ) {  

     pAry[i].onclick = function() {  

     alert(i);  

  }  

 }  

}  

</script>  

</head>  

<body onload="init();">  

<p>产品一</p>  

<p>产品二</p>  

<p>产品三</p>  

<p>产品四</p>  

<p>产品五</p>  

</body>  

</html>

 

解决方式有以下几种

1、将变量 i 保存给在每个段落对象(p)上

function init() {  

 var pAry = document.getElementsByTagName("p");  

 for( var i=0; i<pAry.length; i++ ) {  

   pAry[i].i = i;  

   pAry[i].onclick = function() {  

    alert(this.i);  

   }  

 }  

}

 

2、加一层闭包,i以函数参数形式传递给内层函数

function init3() {  

 var pAry = document.getElementsByTagName("p");  

 for( var i=0; i<pAry.length; i++ ) {  

  (function(arg){    

    pAry[i].onclick = function() {    

     alert(arg);  

    };  

  })(i);//调用时参数  

 }  

}  

 

3、加一层闭包,i以局部变量形式传递给内存函数

function init4() {  

 var pAry = document.getElementsByTagName("p");  

 for( var i=0; i<pAry.length; i++ ) {   

  (function () {  

   var temp = i;//调用时局部变量  

   pAry[i].onclick = function() {   

    alert(temp);   

   }  

  })();  

 }  

}

 

 

 

相关文章
|
2月前
|
JavaScript 前端开发
js小数运算出现的问题(精度丢失)及解决办法-亲测有效
JavaScript浮点数运算存在精度丢失问题,如0.1+0.2不等于0.3。原因是十进制小数转二进制时可能出现无限循环,导致舍入误差。本文提供一种精度处理方法,通过将小数转为整数运算后再还原,实现加减乘除的精确计算,解决常见浮点运算误差问题。
492 0
|
自然语言处理 JavaScript 前端开发
深入理解JavaScript中的闭包:原理与实战
【10月更文挑战第12天】深入理解JavaScript中的闭包:原理与实战
|
9月前
|
前端开发 JavaScript Java
JavaScript闭包深入剖析:性能剖析与优化技巧
JavaScript 闭包是强大而灵活的特性,广泛应用于数据封装、函数柯里化和事件处理等场景。闭包通过保存外部作用域的变量,实现了私有变量和方法的创建,提升了代码的安全性和可维护性。然而,闭包也可能带来性能问题,如内存泄漏和执行效率下降。为优化闭包性能,建议采取以下策略:及时解除对不再使用的闭包变量的引用,减少闭包的创建次数,使用 WeakMap 管理弱引用,以及优化闭包结构以减少作用域链查找的开销。在实际开发中,无论是 Web 前端还是 Node.js 后端,这些优化措施都能显著提升程序的性能和稳定性。
226 70
|
7月前
|
存储 JavaScript 前端开发
|
9月前
|
自然语言处理 JavaScript 前端开发
当面试官再问我JS闭包时,我能答出来的都在这里了。
闭包(Closure)是前端面试中的高频考点,广泛应用于函数式编程中。它不仅指函数内部定义的函数,还涉及内存管理、作用域链和垃圾回收机制。闭包可以让函数访问其外部作用域的变量,但也可能引发内存泄漏等问题。通过合理使用闭包,可以实现模块化、高阶函数和回调函数等应用场景。然而,滥用闭包可能导致代码复杂度增加、调试困难以及潜在的性能问题。为了避免这些问题,开发时应谨慎处理闭包,避免不必要的嵌套,并及时清理不再使用的变量和监听器。
397 16
当面试官再问我JS闭包时,我能答出来的都在这里了。
|
8月前
|
消息中间件 JavaScript 前端开发
最细最有条理解析:事件循环(消息循环)是什么?为什么JS需要异步
度一教育的袁进老师谈到他的理解:单线程是异步产生的原因,事件循环是异步的实现方式。 本质是因为渲染进程因为计算机图形学的限制,只能是单线程。所以需要“异步”这个技术思想来解决页面阻塞的问题,而“事件循环”是实现“异步”这个技术思想的最主要的技术手段。 但事件循环并不是全部的技术手段,比如Promise,虽然受事件循环管理,但是如果没有事件循环,单一Promise依然能实现异步不是吗? 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您
|
8月前
|
缓存 自然语言处理 JavaScript
JavaScript中闭包详解+举例,闭包的各种实践场景:高级技巧与实用指南
闭包是JavaScript中不可或缺的部分,它不仅可以增强代码的可维护性,还能在模块化、回调处理等场景中发挥巨大作用。然而,闭包的强大也意味着需要谨慎使用,避免潜在的性能问题和内存泄漏。通过对闭包原理的深入理解以及在实际项目中的灵活应用,你将能够更加高效地编写出简洁且功能强大的代码。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
JavaScript 前端开发
js 闭包的优点和缺点
【10月更文挑战第27天】JavaScript闭包是一把双刃剑,在合理使用的情况下,它可以带来很多好处,如实现数据封装、记忆功能和模块化等;但如果不注意其缺点,如内存泄漏、变量共享和性能开销等问题,可能会导致代码出现难以调试的错误和性能问题。因此,在使用闭包时,需要谨慎权衡其优缺点,根据具体的应用场景合理地运用闭包。
313 58
|
缓存 JavaScript 前端开发
js 闭包
【10月更文挑战第27天】JavaScript闭包是一种强大的特性,它可以用于实现数据隐藏、记忆和缓存等功能,但在使用时也需要注意内存泄漏和变量共享等问题,以确保代码的质量和性能。
262 7
|
JavaScript
js动画循环播放特效源码(上班族的一天)
js动画循环播放特效是一段实现了包含形象的卡通小人吃、睡、电脑工作的网页动画,js循环动画,简单的画面设计。非常丝滑有意思,欢迎对此代码感兴趣的朋友前来下载参考。
112 2

热门文章

最新文章