我们先看一个正常的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其他资料来加深印象(百度是基本上搜不到什么有用的文章的)。

JS中for循环里面的闭包问题的原因及解决办法的更多相关文章

  1. visual studio code的python编程中遇到的SyntaxError:invalid syntax问题的原因和解决办法

    一.问题重现描述 1.最开始,正常执行语句 2.当我在"终端窗口"输入python进入交互模式后,再选择默认的"在终端中运行python文件"运行代码报错 3. ...

  2. bootstrap table 生成的表格里动态添加HTML元素按钮,JS中添加点击事件,点击没反应---解决办法

    bootstraptable中onExpandRow属性---js  方法添加的 html代码,然后给这代码里面的 元素 添加 事件,却获取不该元素.(称之为未来元素),由于是未来的 所以现在没有这个 ...

  3. Node.js中使用pipe拷贝大文件不能完全拷贝的解决办法

    原来的代码如下: var readable = fs.createReadStream( filepath ); var writable = fs.createWriteStream( outFil ...

  4. 聊一下JS中的作用域scope和闭包closure

    聊一下JS中的作用域scope和闭包closure scope和closure是javascript中两个非常关键的概念,前者JS用多了还比较好理解,closure就不一样了.我就被这个概念困扰了很久 ...

  5. js中的循环语句

    js中的循环语句可分为三种:1.while:2.do……while:3.for. while的语法为 while (exp) {    //statements;} var a=1,b=0; whil ...

  6. js中的循环

    js中的循环是我们经常要用到的,现在进行一些归纳. 一.javascript种的循环. 1.循环对象 var o = { name: 'Jack', age: 20, city: 'Beijing' ...

  7. 对js中局部变量、全局变量和闭包的理解

    对js中局部变量.全局变量和闭包的理解 局部变量 对于局部变量,js给出的定义是这样的:在 JavaScript函数内部声明的变量(使用 var)是局部变量,所以只能在函数内部访问它.(该变量的作用域 ...

  8. js中for循环的研究

    转自:http://blog.csdn.net/lushuaiyin/article/details/8541500 <html> <body> <b><ce ...

  9. java和js中for循环的区别

    java中for循环,先执行语句后循环 for (int i=1;i<10;i++){ for(int b=1;b<=i;b++){ System.out.print(b+"*& ...

随机推荐

  1. 老生常谈的Javascript作用域问题

    在前端学习中,作用域这个问题一直被广泛提起,什么是作用域,什么又是作用域链?在Javascript中,怎么去理解这些概念都是学好这门语言的关键,所以在学习前端开发的过程中,我需要也很有必要去学习和总结 ...

  2. android R 文件生成不了

    在android中比较头疼的是R文件生成不了.今天总结一下R文件生成不了的一些原因和解决方法 1. xml文件有错, 如果在res文件中的xml文件有错,android不会自动生成R文件,此时仔细查看 ...

  3. silverlight 生成图表 WCF 解析XML代码.svc.cs 文件

    silverlight 调用wcf 文件代码 private ListItem AnalyzeXML(string XMLCode, string Reportdate, string ChartNa ...

  4. hdu2488 dfs

    G - 深搜 基础 Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:65536KB     64bi ...

  5. hdu5672 尺取法

    StringTime Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Subm ...

  6. (搬运工)国内顺利使用Google的另类技巧

    在特殊的地方和特殊的时间,流畅顺利使用Google的方法也会变得很特殊.分享一些奇葩的Google使用方法,通过下列网址也可以使用Google来搜索:http://www.GoogleStable.c ...

  7. Session与Cookie间不得不说的一些事

    在很久很久以前,刚有浏览器和网页的时候,web开发者发现了一个问题,我必须要在客户端这边保存一些东西才能实现某些功能,比如大家喜闻乐见的购物车.用户登录.自动登陆等.但是客户端只有一个浏览器,怎么在用 ...

  8. <Win32_5>深入浅出Win32的计时器

    说起时间,对于我们搞IT的人来说,那是要多重要有多重要.我觉得有价值的时间是给有抱负和有才能的人准备的,因为他们会充分利用,不会让时间失望…… 呵呵,有点儿说远了,还是回归主题吧 Win32的计时器其 ...

  9. hdu 5363Key Set

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5363 Problem Description soda has a set S with n inte ...

  10. oracle ed命令

    今天在弄oracle sqlplus的时候需要写一个存储过程,用ed进入之后,退不出来了. 从网上找到下面的方法处理:   如何退出sqlplus ed操作   今天进入sqlplus ,执行完语句后 ...