主要是看在這幾個版本中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