在對一個MVC項目進行頁面修改時碰到一個Jquery里面奇怪的事情。
在頁面中需要輸出很多Record Id,這些數據是固定長度的數字,為了美觀需要一排一排的輸出到頁面,這里我把它定為每排十個。開始我覺得這是個非常之簡單的任務,立即就在輸出到頁面的語句前加了個IF語句對循環變量i進行判斷,如果i對10求余等於0,那么說明滿十了該加一個換行標簽</br>了(i是從0開始的)。
代碼如下:
for (var i in list) { var str="<span>"+list[i].toString()+"</span>    "; if(i%10==0) str += "</br>"; $('#recordIds').append(str);//此語句將一條數據輸出到頁面 }
出來的結果是這樣的:

沒有達到我們預期的效果,因為第一個數據時i等於0,0對10求余是等於0的,也就是說第一個數據也滿足我們的if條件,所以在輸出時后面加了個換行標簽,但其實第一個數據是不應該加的。好吧,這是我算法的錯誤,再思考一下改了就是。
於是,我想都沒想又開寫了,再加一個對i=0時的判斷不就完事了嘛,修改后的代碼如下:
if(i%10==0&&i!=0) str += "</br>";
好,再運行,看結果:

結果還是有問題,於是我慢慢分析了一下,還是算法的問題。
第一個數據i=0時,確實沒有加</br>了,一切正常,問題出在第一排最后一個數,確定它的i=10, 10對10求余等於0,於是該加</br>,是的,它確實加上了,但由於i是從0開始的,仔細分析一下,應該在i等於9,29,39….這樣的序號時才加</br>。於是思路出來了,我們在對i進行判斷時先讓i加上1再對10進行求余,也就是(i+1)%==0,並且這時也不用考慮i=0的情況了,因為i=0時,i+1對10求余不會等於0,第一個不會換行,這樣就會得到當i=9,29,39….這樣的序號時才加</br>。現在基本可以確定算法是沒有問題的了,如果執行正確的話肯定會得到我想要的結果。
其實分析到這里,除了用(i+1)%==0外,還可以用i%10==9來作為判斷是否加</br>的依據,事后我也試過,用 i%10==9來進行判斷可以工作,沒有任何問題。如果我一開始就用這條語句,那就不會有下面這些問題了,但苦逼的是,我采用的是前者。於是麻煩來了。
我們先看這樣改了之后的結果。
代碼: if((i+1)%10) str += "</br>";
輸出:

根本一個</br>標簽都沒加進去!着實有點坑爹。我們再在瀏覽器里對js進行調試下看一看是什么原因。結果發現if判斷語句對於每個i的取值判斷判斷結果都為假,所以if體內的語句一次都沒有被執行到。

首次進入循環,此刻i=0;

步進到下一條語句繼續執行,此刻的i為0,這個倒是可以為0的,因為i+1后並沒有賦給i,所以i為0。
繼續步進,這里$('#recordIds').append(str);語句的append方法會轉到其他地方執行許多操作,但對我們這里討論的for循環無關,執行完其他操作后,再次回到for循環,進行第二次循環,這時i=1,

步進,然后情況和上面一樣了,在對if 條件語句判斷后結果為假,不執行if體內的語句,直接跳到$('#recordIds').append(str);
我懷疑在js里面,(i+1)這樣的寫法主在if判斷語句里有問題,它無法正確執行,之后試了很多形式進行判斷,只要帶(i+1)的都不行。
難道是括號的問題?於是我把圖2時能夠執行的語句if(i%10==0&&i!=0) str += "</br>"; 改為if((i%10==0)&&(i!=0)) str += "</br>"; if((i%10)==0&&i!=0) str += "</br>";
這兩種形式進行嘗試,按理說括號根本不影響的,我們一樣會得到圖2中的結果。
好吧執行后的結果:

兩種方式都得到了跟圖2一樣的結果,說明加括號顯示地指定一下運算優先極是不會影響我們的程序正常執行的。那為什么(i+1)不行。
好吧,既然(i+1)不行,那我就換一種表達式吧,幸好還有前導自增的形式讓i可以在進行運算前加1,於是我改成了如下的代碼:
if(++i%10==0) str += "</br>";
執行結果:

結果非常完美,正是我想要的。到此,我的需求解決了,但我還是沒搞懂if((i+1)%10==0)出了什么問題。
另外就是,這里雖然解決了需求,我還有個小小的擔心。因為上面使用的是++i,這個表達式是先將i自增1,自增后1后的i是保存在了原來的i中的,也就是在執行if(++i%10==0) str += "</br>";中條件判斷后,i的值其實應該是自增后的值,所以這必然會影響到外面的for循環的循環次數。我們的for循環是用來遍歷表的,把表中每個數據打印出來,正常情況下應該是從i=0到i=list.length.這么多個數,由於我們在每次循環時都將i自增了1,可以預見,輸出結果最后將會比正常情況少一半。
帶着這樣的擔心,我將最最原始沒有改變時的程序運行,讓它輸出5個數據,

再在改后的程序中讓它也設置輸出5條數據:

一模一樣!並沒有像我想的那樣會有數據減少的情況!而且輸出完全一樣,沒有因為i自增而出現減少或者數據隔條輸出的現象。這說明for循環中的i並沒有受到影響,仍然是按照從0遍歷到list對象最后條數據為止進行執行的。
但其實我們知道,在C#,C++或者其他高級語言中,在循環體中對循環變量進行了更改是會影響循環次數的,為此,我建了個C#的ConsoleApplication來展示。
代碼:
namespace ConsoleApplication5 { class Program { static void Main(string[] args) { for (int i = 0; i < 5; i++) { Console.WriteLine("i={0}", i); } } } }
很明顯它會輸出0到4五個數,

現在在循環體內增加類似先前討論中的if代碼,程序現在變為
namespace ConsoleApplication5 { class Program { static void Main(string[] args) { for (int i = 0; i < 5; i++) { Console.WriteLine("i={0}", i); if (++i==2) { Console.WriteLine( "at presenti={0}",i); } } } } }
這時輸出的是:

說明確實會影響循環次數。這是非常明顯的事情,但我還是實驗了一把。
所以,我只能說jQuery里面for遍歷服務器返回的結果時,它的循環變量沒有受到循環體內的改變的影響。但循環體內的i使用的值卻是從當前循環變量那里復制過來的。
1天后。。。
在公司浩哥帶領下,第一個問題原因找出來了。
要從最外層的for循環說起。我們知道C#中用foreach對一個字典進行遍歷時,循環變量並不是單純的從0開始到所遍歷對象長度結束為止的連續數字,而是對應着當前所遍歷對象中的一條記錄。
我們再次用一個C#的ConsoleApplication來說明問題;
這里定義一個Person類,再定義一個包含許多Person實例的列表,為了能夠用foreach遍歷,這里的列表我們用System.Collections.Generic 命名空間下的泛型列表List<>,因為它實現了IEnumerable
接口,可以用foreach進行遍歷。
namespace ConsoleApplication6 { public class Person { public string Name { get; set; } } class Program { static void Main(string[] args) { var persons = new List<Person> { new Person(){Name = "Tom Cat"}, new Person(){Name = "Woody Bird"}, new Person(){Name = "Jemmy Duck"} }; foreach (var i in persons) { Console.WriteLine(i.Name); } } } }

無需多說,當我們在調用i.Name時就已經很清楚此刻的i就是一個Person實例了。

同樣,在javascript中的for in 循環也是遍歷對象或者數組的,通過chrome調試我清楚地看到了我遇到問題的代碼確實是遍歷的一個數組;

數組里一條完整的記錄包含key和value, key代表每條數組中每條記錄的鍵值,即0,1,2….value 表示了正在的數據值,即9117405….在上面的ConsoleApplication例子里foreach循環中的i都代表了它遍歷的對象,但javascipt里有點不一樣,它只表示key, 不包含值部分。所以我們不能調用i.value, 而只能是調用list[i].toString()。但這跟if((i+1)%10==0)為什么執行不成功有什么關系呢,確實沒多大關系,這里我只是把i具體是什么搞得更清楚了。
現在來看為什么if((i+1)%10==0)沒執行成功。對這條語句設斷點在瀏覽器里調試。居然驚訝的發現,此刻i為0,但i+1=01!

坑爹出現在這里,它會把i當成字符串然后和1相加最后得一個“01”字符串!我去。
所以這里若想要得到i+1的數字結果的話,需要我們顯示地進行數據類型的轉換。改成如下代碼一切okay了。
if ((parseInt(i) + 1) % 10 == 0) str += "</br>";
總結:在思索與尋求答案的過程中更正了自己不少錯誤的認識,也學到了很多東西。任何一個小問題都可以觸類旁通產生與之關聯的更多問題,需要我們去發現去思索。寫出來和大家分享,希望能幫助到有類似情況的初學者。
