for ([initialization]; [condition]; [final-expression]) { statement }
initialization
一個表達式 (包含賦值語句) 或者變量聲明。典型地被用於初始化一個計數器。該表達式可使用var或let關鍵字聲明新的變量,使用var聲明的變量不是該循環的局部變量,而是與for循環處在一樣的做用域中。用let聲明的變量是語句的局部變量。該表達式的結果無心義。注意此處的let 和 var 聲明表達式的不一樣點express
condition
一個條件表達式被用於肯定每一次循環是否能被執行。若是該表達式的結果爲true, statement 將被執行。 這個表達式是可選的。若是被忽略,那麼就被認爲永遠爲真。若是計算結果爲假,那麼執行流程將被跳到for語句結構後面的第一條語句。
final-expression
每次循環的最後都要執行的表達式。執行時機是在下一次condition的計算以前。一般被用於更新或者遞增計數器變量。
statement
只要condition的結果爲true就會被執行的語句。 要在循環體內執行多條語句,使用一個塊語句({ ... })來包含要執行的語句。沒有任何語句要執行,使用一個空語句(;)。 可使用break 主動跳出循環數組
setTimeOut等異步函數時:閉包
var arr = [1,3,5,7,9]; for (var i = 0; i < arr.length-1; i++) { setTimeout(function() { console.log("循環的值:"+i); console.log("數組對應的值:"+arr[i]); }, 1000); }
存在閉包時:異步
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; } let boxArr = box(); console.log(boxArr[0]())
這時,會產生與咱們預期所想獲得的效果不一樣的結果,致使出現這種狀況的緣由主要是 for語句表達式中初始化中的變量不是該循環的局部變量(子做用域),而是與for循環處在一樣的做用域中(父做用域)。
所以,解決方案比較流行的有兩種:
第一種:使用let 替代 var 聲明for循環的表達式(推薦)函數
function box() { var arr = []; for (let i = 0; i < 5; i++) { arr[i] = function () { return i; } } return arr; } let boxArr = box(); console.log(boxArr[0]())
var arr = [1,3,5,7,9]; for (let i = 0; i < arr.length-1; i++) { setTimeout(function() { console.log("循環的值:"+i); console.log("數組對應的值:"+arr[i]); }, 1000); }
第二種:使用自執行函數利用閉包特性來達到效果:spa
var arr = [1, 3, 5, 7, 9]; for (var i = 0; i < arr.length ; i++) { (j=>{ setTimeout(() =>{ console.log("循環的值:" + j); console.log("數組對應的值:" + arr[j]); }, 1000); })(i) }
function box() { var arr = []; for (var i = 0; i < 5; i++) { ((j)=>{ arr[j] = ()=> j; })(i); } return arr; } let boxArr = box(); console.log(boxArr[0]()) console.log(boxArr[1]())