主要是看在这几个版本中for循环解决异步问题都是怎样操作的
1、存在的问题
异步事件主要有计时器,鼠标事件,ajax
以写网页的导航为例,比如你的导航是用ul li 标签写的,你想对每个li添加事件,比如加背景,改颜色字体之类的,在js中你在获取li标签的时候,得到的会是一个伪数组(可转真数组[].slice.call()),你会想着循环遍历这个数组然后在这个循环内添加你想要添加的事件,那么这时候就会出现问题,你添加的事件永远得不到你想要的效果,打印下标你会发现永远是li的长度。
2、解析原因
之所以出现上述情况是因为在计算机中for循环是很快的,打你打开浏览器的时候for循环早已经循环结束了,这其中的了解一下js执行代码的顺序问题,在这个循环中for循环为主线程,事件为异步事件,执行代码时会先执行主线程代码,后执行异步事件
3、解决办法
ES4解决办法:
在for循环中加一个闭包(嵌套一个函数)把循环的下标传入这个被嵌套的函数中去,在里面写你想要添加的事件一般这个函数为一个匿名函数。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> li{ height: 56px; width: 70px; background: lightblue; list-style: none; text-align: center; line-height: 56px; float: left; cursor: pointer; } </style> </head> <body> <ul> <li>首页</li> <li>子页1</li> <li>子页2</li> <li>子页3</li> <li>子页4</li> </ul> </body> </html> <script type="text/javascript"> //ES4方法: //获取所有li标签 var Oli = document.getElementsByTagName("li"); //循环遍历每个li并实现点击背景变红 for(var i = 0;i < Oli.length;i++){
//此处嵌套匿名函数作为闭包 (function(index){ Oli[index].onclick = function(){
//此处便利循环先还原背景在给指定的li添加背景 for(var j = 0;j < Oli.length;j++){ Oli[j].style.background = ""; }
//给当前li添加背景色 Oli[index].style.background = "red"; } })(i) } </script>
ES5解决办法:
用forEach(function(value,index))方法,这时候value为li的值,index为li的下标,需要什么直接调来写即可。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> li{ height: 56px; width: 70px; background: lightblue; list-style: none; text-align: center; line-height: 56px; float: left; cursor: pointer; } </style> </head> <body> <ul> <li>首页</li> <li>子页1</li> <li>子页2</li> <li>子页3</li> <li>子页4</li> </ul> </body> </html> <script type="text/javascript"> //ES5方法: //获取所有li标签 var Oli = document.getElementsByTagName("li"); //此方法需要的是真数组,所以先把Oli转真数组 Oli = [].slice.call(Oli); //循环遍历每个li并实现点击背景变红 //利用forEach()方法里的函数是个闭包 Oli.forEach(function(value,index){ value.onclick = function(){ //遍历循环li还原背景色 for(var i = 0;i < Oli.length;i++){ Oli[i].style.background = ""; } //给当前li添加背景色 value.style.background = "red"; } }) </script>
ES6解决办法:
在for循环中定义变量的时候用let,利用let的块级作用域限制功能完美解决for循环的异步问题,写法和ES4没多大区别,但功能却是很强大
(顺便提一下用let定义变量的一些功能 1、块级作用域限制。2、没有声明提升。3、暂时性死区)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> li{ height: 56px; width: 70px; background: lightblue; list-style: none; text-align: center; line-height: 56px; float: left; cursor: pointer; } </style> </head> <body> <ul> <li>首页</li> <li>子页1</li> <li>子页2</li> <li>子页3</li> <li>子页4</li> </ul> </body> </html> <script type="text/javascript"> //ES6方法: //获取所有li标签 let Oli = document.getElementsByTagName("li"); //循环遍历每个li并实现点击背景变红 //利用let定义变量有块级作用域限制的特点实现类似闭包的功能 for(let i = 0;i < Oli.length;i++){ Oli[i].onclick = function(){ //循环遍历li还原背景色 for(let j = 0;j < Oli.length;j++){ Oli[j].style.background = ""; }
//给当前li添加背景色 Oli[i].style.background = "red"; } } </script>
效果实现如上图。
本文叙述过于抽象,若有想了解的小伙伴,可联系我:
qq:2604874347