今天一個做后端的同事問了我一個JS的問題:
有個循環(huán)窍仰,循環(huán)一個異步回調(diào)供炼,為啥回調(diào)引用的循環(huán)值都是最后一步循環(huán)的循環(huán)值?然后涨薪,又有些時候無論什么循環(huán)值都得不到骑素?
好吧,JavaScript跟PHP的循環(huán)有時候確實不一樣刚夺,JavaScript的函數(shù)有同步函數(shù)跟異步函數(shù)的區(qū)分献丑,PHP里面沒這種概念,拿PHP的常識來理解JavaScript有時候行不通侠姑。關(guān)于JS異步機制的研究创橄,看我另一篇JS異步執(zhí)行機制理解。
我想了想莽红,他說的“什么循環(huán)值也得不到的”妥畏,應(yīng)該是下面這個情況:
<script type="text/javascript">
var arr = [1,3,5,7,9];
var arrLength = arr.length;
for (var i = 0; i < arrLength; i++) {
setTimeout(function() {
console.log(i);
console.log(arr[i]);
}, 2000);
}
</script>
結(jié)果是:
5
undefined
5
undefined
5
undefined
5
undefined
5
undefined
for循環(huán)有一個特點邦邦,就是“i判斷失敗一次才停止”。所以醉蚁,i在不斷的自加1的時候燃辖,直到i等于5,i才失敗网棍,這時候循環(huán)體不再執(zhí)行黔龟,會跳出,所以i等于5沒錯滥玷。那么為什么5次循環(huán)的i都等于5氏身?原因就是setTimeout()的回調(diào),也就是console.log(i);console.log(arr[i]);
被壓到任務(wù)隊列的最后惑畴,for循環(huán)是同步任務(wù)蛋欣,所以先執(zhí)行,等于是空跑了5次循環(huán)如贷。于是陷虎,i都等于5之后,console.log(i);console.log(arr[i]);
剛開始第一次執(zhí)行倒得,當(dāng)然輸出全是5泻红。
然后,同事說霞掺,有時候JS的for循環(huán)谊路,永遠只得到最后一個循環(huán)值,那其實他用的是for...in...循環(huán)菩彬。具體不多解釋了缠劝。
我既然聽了他的問題,就要給他解決方案骗灶。
我先建議他用自執(zhí)行函數(shù)傳參惨恭,這樣自執(zhí)行函數(shù)內(nèi)部形成了局部作用域,不受外部變量變化的影響耙旦。范例代碼是:
<script type="text/javascript">
var arr = [1,3,5,7,9];
var arrLength = arr.length;
for (var i = 0; i < arrLength; i++) {
(function(i) {
setTimeout(function() {
console.log('i是' + i);
console.log('value是' + arr[i]);
}, 2000);
})(i);
}
</script>
得到:
不但解決了undefined的問題脱羡,而且解決了異步函數(shù)傳參的問題。
然后我把范例代碼給了他免都。然而锉罐,他的JS代碼寫的太亂,拿這個例子改居然改不對绕娘。于是我又給了一個jQuery方案給他:
<script type="text/javascript">
var arr = [1,3,5,7,9];
$.each(arr, function(key, value) {
setTimeout(function() {
console.log('i是' + key);
console.log('value是' + value);
}, 2000);
});
</script>
用jQuery的$.each()脓规,自帶回調(diào)函數(shù),形成了函數(shù)作用域险领,這娃最終解決了問題侨舆。