博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深入理解闭包系列第四篇——常见的一个循环和闭包的错误详解
阅读量:6113 次
发布时间:2019-06-21

本文共 1568 字,大约阅读时间需要 5 分钟。

前面的话

  关于常见的一个和的错误,很多资料对此都有文字解释,但还是难以理解。本文将以图示的方式来对此进行更直观的解释,以及对此类需求进行推衍,得到更合适的解决办法

 

犯错

function foo(){    var arr = [];    for(var i = 0; i < 2; i++){        arr[i] = function(){            return i;        }    }    return arr;}var bar = foo();console.log(bar[0]());//2

  以上代码的运行结果是2,而不是预想的0。接下来用执行环境图示的方法,详解到底是哪里出了问题

  执行流首先创建并进入全局执行环境,进行过程。执行流执行到第10行,创建并进入foo()函数执行环境,并进行声明提升。然后执行第2行,将arr赋值为[]。然后执行第3行,给arr[0]和arr[1]都赋值为一个匿名函数。然后执行第8行,以arr的值为返回值退出函数。由于此时有闭包的存在,所以foo()执行环境并不会被销毁

  执行流进入全局执行环境,继续执行第10行,将函数的返回值arr赋值给bar

  执行流执行第11行,访问bar的第0个元素并执行。此时,执行流创建并进入匿名函数执行环境,匿名函数中存在i,需要使用其作用域链匿名函数 -> foo()函数 -> 全局作用域进行查找,最终在foo()函数的作用域找到了i,然后在foo()函数的执行环境中找到了i的值2,于是给i赋值2

  执行流接着执行第5行,以i的值2作为返回值返回。同时销毁匿名函数的执行环境。执行流进入全局执行环境,接着执行第11行,调用内部对象console,并找到其方法log,将bar[0]()的值2作为参数放入该方法中,最终在控制台显示2

   由此我们看出,犯错原因是在循环的过程中,并没有把函数的返回值赋值给数组元素,而仅仅是把函数赋值给了数组元素。这就使得在调用匿名函数时,通过作用域找到的执行环境中储存的变量的值已经不是循环时的瞬时索引值,而是循环执行完毕之后的索引值

 

IIFE

  由此,可以利用传参和来创建多个执行环境来保存循环时各个状态的索引值。因为是按值传递的,不同参数的函数被调用时,会创建不同的

function foo(){    var arr = [];    for(var i = 0; i < 2; i++){        arr[i] = (function fn(j){            return function test(){                return j;            }        })(i);    }    return arr;}var bar = foo();console.log(bar[0]());//0

 

块作用域

  使用IIFE还是较为复杂,使用块作用域则更为方便

  由于可以将索引值i重新绑定到了循环的每一个迭代中,确保使用上一个循环迭代结束时的值重新进行赋值,相当于为每一次索引值都创建一个执行环境

function foo(){    var arr = [];    for(let i = 0; i < 2; i++){        arr[i] = function(){            return i;        }    }    return arr;}var bar = foo();console.log(bar[0]());//0

 

最后

  在编程中,如果实际和预期结果不符,就按照代码顺序一步一步地把执行环境图示画出来,会发现很多时候就是在想当然

  以上

转载地址:http://locka.baihongyu.com/

你可能感兴趣的文章
Android UI优化——include、merge 、ViewStub
查看>>
Office WORD如何取消开始工作右侧栏
查看>>
Android Jni调用浅述
查看>>
CodeCombat森林关卡Python代码
查看>>
第一个应用程序HelloWorld
查看>>
(二)Spring Boot 起步入门(翻译自Spring Boot官方教程文档)1.5.9.RELEASE
查看>>
Android Annotation扫盲笔记
查看>>
React 整洁代码最佳实践
查看>>
聊聊架构设计做些什么来谈如何成为架构师
查看>>
Java并发编程73道面试题及答案
查看>>
iOS知识小集·设置userAgent的那件小事
查看>>
移动端架构的几点思考
查看>>
Tomcat与Spring中的事件机制详解
查看>>
Spark综合使用及用户行为案例区域内热门商品统计分析实战-Spark商业应用实战...
查看>>
初学者自学前端须知
查看>>
Retrofit 源码剖析-深入
查看>>
企业级负载平衡简介(转)
查看>>
ICCV2017 论文浏览记录
查看>>
科技巨头的交通争夺战
查看>>
当中兴安卓手机遇上农行音频通用K宝 -- 卡在“正在通讯”,一直加载中
查看>>