我们先看一个正常的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]。
解决方案1
在看解决方案一之前,我们先看一下匿名函数的自我执行:
匿名函数自我执行的写法是,在函数体外面加一对圆括号,形成一个表达式,在圆括号后面再加一个圆括号,里面可传入参数。
例如下代码:
(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]);
通过给匿名函数传参,而传递的这个参数i是每次执行for循环里面的i,每次传递的参数i的值都不一样,匿名函数里面的num接收传递的参数i,所以box()最终输出结果为[0,1,2,3,4]
解决方案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],
解决方案3
如果将一个匿名函数自我执行的时候赋值给一个变量,那么这个匿名函数中的圆括号的可以去掉的,看下面代码,
var tip = function(){ //这样把匿名函数自我执行的时候赋值给一个变量,那么圆括号是可以去掉的 alert('lee'); }();
利用匿名函数的这一特点,我们可以将解决方案1中的代码改进一下:
function box(){ var arr = []; for(var i=0;i<5;i++){ arr[i] = function(num){ return num; }(i); } return arr; } //alert(box()); //alert(box()[1]); //alert(box().length); alert(box()[4]);
匿名函数在执行的时候他本身就传递给了一个变量arr[i],所以匿名函数的圆括号是可以去掉的。
以上就是几种解决for循环中闭包的办法,当然还有更多办法,大家可自行google或者bing其他资料来加深印象(百度是基本上搜不到什么有用的文章的)。
相关推荐
浅谈JavaScript for循环闭包 在JavaScript中,for循环和闭包是两个非常重要的概念。本文将对JavaScript for循环和闭包进行浅谈,并提供六种解决方案来解决for循环中的闭包问题。 首先,让我们来看一个例子。我们有...
通过这些方法,我们可以确保每个事件处理函数都能够正确地访问到循环中的变量,从而解决闭包问题。了解并熟练掌握闭包和动态事件绑定是JavaScript开发者必备的技能,这对于编写高效、无bug的代码至关重要。在实际...
然而,当闭包与循环结合时,可能会遇到一些预期之外的问题,正如标题和描述中提到的那样。本文将深入探讨这个问题,并介绍如何通过使用自执行的匿名函数来解决。 首先,让我们看一个简单的例子,这个例子展示了在不...
总结来说,解决JavaScript中的闭包问题通常需要理解作用域和变量生命周期。当在循环中使用闭包时,要确保每个闭包有自己的变量副本,而不是共享同一个变量。通过使用IIFE或者将变量绑定到`this`或`let`关键字声明的...
然而,在处理JavaScript中的闭包时,for循环常常会带来一些特别的问题。闭包是指有权访问另一个函数作用域中的变量的函数。这个问题通常出现在循环结构中,比如在为DOM元素的事件处理器(如点击事件)绑定函数时。这...
然而,由于JavaScript的作用域和闭包特性,代码中的for循环并没有按预期工作。当循环结束时,`i`的值为4,因此无论点击哪个按钮,都会弹出数字4。这是因为事件处理程序在循环中创建时,它们共享同一个`i`变量的引用...
在JavaScript编程中,for循环是常见的迭代工具,用于遍历数组或对象的元素。然而,在处理事件绑定,尤其是涉及到异步操作时,如点击事件,可能会遇到一个常见问题:循环内的变量共享导致输出不按预期进行。这个问题...
这里,立即执行的匿名函数(IIFE)创建了一个新的作用域,使得每次循环都能保持对`i`的独立引用,避免了闭包中的变量共享问题。 总的来说,闭包是JavaScript中一个非常重要的概念,它提供了维护变量状态和访问私有...
在讨论JavaScript编程语言时,匿名函数和闭包是两个重要的概念,它们在函数式编程和模块化代码设计中扮演着核心角色。匿名函数是没有具体名称的函数,它们可以是独立的,也可以是表达式的一部分,通常用于定义临时...
在JavaScript编程中,常常会遇到在for循环中添加事件监听的情况,特别是当涉及到动态创建元素或者处理数组时。本文聚焦于一个常见的问题:在for循环中嵌套点击事件,导致点击一次触发多次弹窗,且显示相同值。这个...
另一个例子展示了闭包在循环中的应用,以及如何防止共享变量的问题: ```javascript function buildFunctions() { var funcArr = []; for (var i = 0; i ; i++) { funcArr.push(function() { console.log(i); ...
这是因为 `setTimeout` 中的匿名函数形成了一个闭包,保留了对循环变量 `i` 的引用。 ##### 4.2 Internet Explorer 内存泄漏问题 在早期版本的 Internet Explorer 中,由于某些内部实现的缺陷,闭包可能导致内存...
### 3.var处理for循环.md #### 知识点概览 本文档主要探讨了在JavaScript中使用`var`关键字处理`for`循环时的一些特殊技巧及其背后的原理。此外,文档还简要提及了`let`关键字的使用,并通过一个具体的示例来展示...
// for循环内定义闭包方法 for(var i = 0; i ; i++) { var div = els[i]; a(div); } function a(o) { o.onclick = function() { alert(o.innerHTML); } } ``` 3. 通过使用立即执行函数表达式(IIFE)来...
JavaScript中的闭包是一种强大的特性,它允许函数访问和操作其外部作用域的变量,即使在其外部作用域已经结束之后。在这个示例中,问题在于事件处理函数引用了外部的`i`变量,而不是创建自己的局部副本。这导致了在...
当使用for循环为多个元素绑定点击事件时,你可能会发现所有元素的事件回调函数都使用了最后一次循环变量的值,这是因为循环变量i在闭包的作用域中被共享。为了解决这个问题,我们可以采取两种策略:利用闭包或者使用...
虽然上述代码使用了闭包来解决问题,但通常我们不推荐在回调函数中使用闭包来解决问题。更好的实践方法是使用数组或其他数据结构来管理回调函数,例如利用jQuery的Deferred对象和Promise,或者使用ES6的async/await...