在JS中主要的循環(huán)包含
- while
- do while
- for
- for-in
在這些循環(huán)中,使用最多的是for循環(huán),下面將從幾個(gè)方面來(lái)具體說(shuō)說(shuō)for循環(huán)
1.表達(dá)式:
for (var i=0;i<10;i++){
console.log(i);//打印的結(jié)果為:0123456789
}
上面這段代碼是for循環(huán)最常見(jiàn)的寫(xiě)法.其中包含
var i=0 初始化部分,在進(jìn)入循環(huán)前執(zhí)行
i<10;循環(huán)成立的條件,為表達(dá)式,只有當(dāng)真時(shí)才會(huì)執(zhí)行循環(huán)體中的表達(dá)式
i++ 自增部分,每次執(zhí)行循環(huán)完后才會(huì)調(diào)用的表達(dá)式
{console.log(i)} 循環(huán)體
for(var i=0,name='zhangsan';i<10;i++){
console.log(name+i);//打印的結(jié)果為:zhangsan0到zhangsan9
}
和上面的例子確實(shí)沒(méi)什么不同,只是在初始化部分添加了一個(gè)參數(shù)name='zhangsan',意思無(wú)非就是聲明了一個(gè)叫name的變量,也就說(shuō)明了其實(shí)i=0;就是一個(gè)初始化變量的作用.
for(var i=0;
(function()
{if(i<10)
return true;
return false
})();i++){
console.log(i);//打印的結(jié)果為:0到9
}
上面的代碼我畫(huà)蛇添足的在條件判斷中使用了一個(gè)立即執(zhí)行函數(shù),主要是證明條件部分是一個(gè)表達(dá)式,在for循環(huán)每次循環(huán)時(shí)都會(huì)執(zhí)行該表達(dá)式,繼續(xù)循環(huán)的條件是該表達(dá)式的值為真(true)
for(var i=0;i<10;i>5?i++:i+=2){
console.log(i);//打印結(jié)果為0 2 4 6 7 8 9
}
我在第三部分(自增部分)添加了寫(xiě)了一個(gè)三元運(yùn)算符,目的也是為了證明這第三部分也是一個(gè)表達(dá)式,在每一次執(zhí)行完循環(huán)后都會(huì)執(zhí)行該表達(dá)式,從而確定i的值.
既然每次執(zhí)行都會(huì)執(zhí)行這個(gè)表達(dá)式,那么我們也可以這樣寫(xiě):
for(var i=0;i<10;i++,console.log(i)){}
和
for (var i=0;i<10;i++){
console.log(i);
}
上面兩個(gè)表達(dá)式輸出的結(jié)果是相同的嗎?
答應(yīng)是不同的,第一個(gè)先執(zhí)行的i++,再執(zhí)行的console.log() 而第二個(gè)先執(zhí)行的console.log(),再執(zhí)行的i++ ,原因嘛就是上面說(shuō)的for表達(dá)式的自增部分是每一次循環(huán)結(jié)束后才執(zhí)行的表達(dá)式
如果改寫(xiě)下:
for(var i=0;i<10;console.log(i),i++){}
和
for (var i=0;i<10;i++){
console.log(i);
}
以上兩個(gè)打印結(jié)果就相同了.
2.還可以怎么寫(xiě)?
上面的 初始化,條件,自增部分都可以為空,我們依次來(lái)看看他們的寫(xiě)法
var i=0;
for(;i<10;i++){
console.log(i)//打印結(jié)果為:0到9
}
只是將初始化提前了.
var i=0;
for(;;i++){
console.log(i)//打印結(jié)果為:0到99
if(i==99){break;}
}
如果條件表達(dá)式為空,則表示死循環(huán),為了避免內(nèi)存溢出我這添加了一個(gè)i==99的條件和break;讓循環(huán)終止
var i=0;
for(;;){
console.log(i)//打印結(jié)果為:0到98
i++;
if(i==99){break;}
}
如果自增表達(dá)式為空,也表示死循環(huán),為了避免內(nèi)存溢出我這添加了一個(gè)i==99的條件和break;讓循環(huán)終止
3.循環(huán)體中的async會(huì)出什么幺蛾子?
for(var i=0;i<3;i++){
setTimeout(function(){
console.log(i);//等等一秒打印結(jié)果為3個(gè)3
},1000);
}
如何避免:
for(var i=0;i<3;i++){
(function(i){
setTimeout(function(){
console.log(i);//等等一秒打印結(jié)果為0,1,2
},1000);
})(i)
}
原因? 在下面分析
4.為什么使用ES6的let關(guān)鍵字不會(huì)有問(wèn)題?
我們看下面的代碼:
普通JS for中的async:
for(var i=0;i<3;i++){
setTimeout(function(){
console.log(i);//等等一秒打印結(jié)果為3個(gè)3
},1000);
}
使用閉包 for async:
for(var i=0;i<3;i++){
setTimeout(function(){
console.log(i);//等等一秒打印結(jié)果為0 1 2
},1000);
}
使用ES6 let 關(guān)鍵字的for async:
for(var i=0;i<3;i++){
setTimeout(function(){
console.log(i);//等等一秒打印結(jié)果為0 1 2
},1000);
}
其中 使用閉包的for async 和ES6 let 的for async 輸出結(jié)果是相同的:
下面我用一些偽代碼來(lái)說(shuō)明一些原因:
我們先來(lái)為普通的for寫(xiě)一些偽代碼:
function test(){
var i=0;
{
setTimeout(function(){
console.log(i);
},1000);
i++;
}
{
setTimeout(function(){
console.log(i);
},1000);
i++;
}
{
setTimeout(function(){
console.log(i);
},1000)
i++;
}
}
test();//輸出結(jié)果為:3個(gè)3
等待1秒后i的值已經(jīng)經(jīng)過(guò)了3次i++(在for中每一次循環(huán)都會(huì)執(zhí)行自增表達(dá)式) 當(dāng)執(zhí)行console.log()的時(shí)候 此時(shí)的i已經(jīng)變成了3,則每次打印都為3
下面是閉包的for async 偽代碼:
function test(){
var i=0;
{
function _0(i){
setTimeout(function(){
console.log(i);
},1000)
}
_0(i);
i++;
}
{
function _1(i){
setTimeout(function(){
console.log(i);
},1000)
}
_1(i);
i++;
}
{
function _2(i){
setTimeout(function(){
console.log(i);
},1000)
}
_2(i);
i++;
}
}
test()//打印結(jié)果為0 1 2
在ES6之前,JS的最小作用域是函數(shù),并且聲明的變量和函數(shù)都會(huì)得到提升,上面的例子中_0將i當(dāng)成是參數(shù),當(dāng)執(zhí)行到_0函數(shù)時(shí),會(huì)在_0函數(shù)內(nèi)部最開(kāi)始就聲明一個(gè)變量i并且賦值為0,所以在setTimeout打印時(shí)引用的i是_0函數(shù)中的i變量,也就是0,依次的,_1 函數(shù) _2 函數(shù)也是相同的
而在ES6中for循環(huán)應(yīng)該是這樣的:
function test(){
let i=0;
{
setTimeout(function(){
console.log(i);
},1000);
i++;
}
{
setTimeout(function(){
console.log(i);
},1000);
i++;
}
{
setTimeout(function(){
console.log(i);
},1000)
i++;
}
}
test();//打印結(jié)果依然是3個(gè)3
那么是否是這樣呢?
function test(){
{
let i=0;
setTimeout(function(){
console.log(i);
},1000);
}
{
let i=1;
setTimeout(function(){
console.log(i);
},1000);
}
{
let i=2;
setTimeout(function(){
console.log(i);
},1000)
}
}
test()//執(zhí)行結(jié)果為0 1 2