# 十、 迴圈 `loop` ###### tags: `JavaScript` `JS101` `2020六月第五週` `進度筆記` `Lidemy心得` `7/7` --- ## 1. 迴圈基本介紹 一直 redo 同件事,大概像是重跑操場好幾圈,通常也有個終止條件,像是跑到天黑停下來; 也有無窮迴圈,瘋狂一直跑而且跳脫不了循環,通常在沒有給終止條件,或是設錯終止條件才會發生。 --- ## 2. 非 JS 的迴圈介紹 ### 這是 JS 沒有的語法: `label` 和 `goto` , 如假設要印出 1 到 10 的情況: console.log(1) console.log(2) console.log(3) .... .... . . . console.log(10) /* 這段印不出來; 那假設要印出更多,印到 100 , 甚至 10000 次的情況呢 ? 這樣可能會沒有效益而且無法規模化,因此需要有方法來規模化。 */ --- ### 規模化的方法: var i = 1 console.log(i) i++ // 等同 i = i+1 , 也就是 i+=1; 會算出 i=2; /* 如果可以用指令一直回到 console.log(i) 這行, 就會算出 3, 4..., 直到 10 , 甚至 100 , 10000; 就可以達成迴圈的功能; 這只會印出 1 。 */ --- ### `goto` where ? 的場合: 承接上面的式子, JS 雖沒這個語法,但概念就是達成迴圈。 var i = 1 loop: // 執行每行程式後碰到 loop 後會停下。 console.log(i) i++ // 等同 i = i+1 , 也就是 i+=1; 會算出 i=2; goto loop // goto 要接 label 為 loop ; /* 這樣會從 var i = 1 開始跑,經過 loop 先不理他,一路跑到 goto loop 後再回 到 loop: , 然後往 下跑 console.log(2) , 再往下跑 i++ , 接著跑 goto loop 後再回到 loop , 如此重複,但是因為沒有煞車所以會停不下來。 */ --- ### 所以我們需要煞車 var i = 1 loop: // 執行每行程式後碰到 loop 後會停下。 console.log(i) i++ // 等同 i = i+1 , 也就是 i+=1; 會算出 i=2; if (i<=100) { goto loop // goto 要接 label 為 loop ; } else { // 但其實 else 可以不用; console.log('finished!') } /* 這樣會從 var i = 1 開始跑,經過 loop 先不理他,一路跑到 goto loop 後再回 到 loop: , 然後往下跑 if 直到 i 值超過 100 後,因為有了 else 煞車才會停下來; 如果最後 i 值超過 100 後把 i 值 log 出來 console.log('i=', i) , 因為要符合 (i<=100) 這個條件時 , i 已經是 100 了,因此 100 = 100+1, 會印出 101 。 */ 如此可以達到迴圈的功能,一直重複做同件事,和有終止條件,如果沒有終止條件,無窮迴圈會吃掉電腦資源 , ctrl+c 可以終止。 --- ## 3. 要怎麼用 JS 執行迴圈 ? ### JS 執行迴圈的儀式 常用的情形,第一種是 do...while... 同時做: // 要記得 ( ) 內是條件,而 { } 內是區塊; var i = 1 do { console.log(i) i++ } while(i<=100) console.log('i=', i) // 會一直印直到 101 才停。 只要 while(i<=100),條件是 true 的話,就會回到 do 那行,即無窮迴圈;如果是 fales 即值超過 101 時,會跳出迴圈; 如果跑迴圈不確定怎麼跑的時候記得寫下來,讓自己跟電腦一樣一行一行執行。 --- 第二種,如果是 while(true) 的情況,要怎麼一擊脫離 ?: var i = 1 do { console.log(i) i++ if (i>100) { // 如果設 i<=100 , 式子一下就斷掉囉; break // 執行到這個 break 就會中斷並跳出區塊, } } while(true) console.log('i=', i) // 一樣印直到 101 才停。 而當 `while(true)` ,條件是 true 的話,是無窮迴圈,因此要有辦法脫離,所以上面有設定 i>100 值; 而如果是 `while(false)` 會先跑第一行印出 1 , 而執行 i++ 後值為 2 , 因為 false 的關係即值永遠不會達到 i>100 因此會中斷迴圈; --- 第三種,街機遊戲一直投代幣停不下來 , continue : 無窮迴圈的場合。 var i = 1 do { if (i%2 === 1) { continue // 如果 continue 設在這裡,會一直往上跳到 do , 一直都是 1 的情況 } console.log(i) i++ } while(i<=100) console.log('i=', i) // 這是無窮迴圈~ 這情況是: i => 1 do if ()i%2 ===1) => true continue while(i<=100) => true do if ()i%2 ===1) => true continue while(i<=100) => true 會一直重複...但 continue 是可以跳過迴圈這圈的,但在這個範例中成為無窮迴圈。 --- 例如我只要印出 1 ~ 101 中的 i++ 偶數行: var i = 1 do { console.log(i) i++ // 如果是 i-- 會變成無窮迴圈。 if (i%2 === 1) { continue // 會跑到下一圈,而讓基數被 console.log('i++', i) 忽略掉, 使基數不會印出 i++ ; } console.log('i++', i) } while(i<=100) console.log('i=', i) // 'i=' 會等於 'i:' // 偶數會印出 i++ 的字串。 宣告變數後開始跑,跑到 `while` 看到條件 `i<=100` , 如果值還是 <=100 就接著跳回 `do` , 然後一直做下去直到值超過 101 ; 同時 `if (i%2 === 1) {` 會跑到下一圈,而讓基數被 console.log('i++', i) 忽略掉, 使基數不會印出 i++ , 在下行有 `continue` 的情況就會跳出這段迴圈使偶數印出 i++ ; 如果給 `if (i <=10)` 就會變成 1 到 10 都不會印出 i++ ; 而給 `if (i>=1)` 和 `if (i <=1000)` 就會跟第二種情況一樣直到 印出 101 才停。 --- 而突然終止迴圈的情況: var i = 1 do { console.log(i) i++ if (i <=1000) { break } console.log('i++', i) // 這行沒有起到作用; } while(i<=100) console.log('i=', i) // 會印出 1 且下行是 i= 2 。 因為一開始宣告 i= 1 , 往下就印出 1 ,因此繼續執行 i++ 時,值為 2 , 而接著往下執行 `if (i <=1000) {` 則發現因為值 <=1000 , 因此到 break 就終止了,最後往下執行印出 i= 2 。 --- ## 4. 而在瀏覽器的執行環境場合 要看場合的方法: <script> debugger var i = 1 do { console.log(i) i++ } while(i<=100) console.log('i=', i) </script> 用瀏覽器開啟存下上面這行文字的 html 格式檔案,開發人員選項中可以看到 sources debugger 偵錯模式:按下 F5 會在 Chrome 中停在 debugger 行, 按下 step 或是 F9 會繼續往下; 如果按下 Watch 輸入 i , Enter 後會看到 i 的數值,用這個可以檢查程式的問題; 也能在每行設中斷點,再按下 F8 或是 Resume script execution 就會停在中斷點: ![](https://i.imgur.com/XA1KboO.png) --- ## 5. 擺脫輪迴 while do...while...的使用情況是先做某件事情,最後到 while 判斷條件: var i = 1 do { console.log(i) i++ } while(i<=100) console.log('i=', i) // 印到 101 為止。 在某些 check 覺得第一次一定要做的場合會用到 do...while... 。 --- 而只用 while 的情況就會變成先判斷條件,和執行區塊: var i = 1 while(i<=100) { // 如果條件設定成 true , 就會變成無窮迴圈 console.log(i) i++ } console.log('i=', i) // 跟 do...while... 一樣印到 101 為止。 // 如果再更精簡可以變成: var i = 1 while(i<=100) { console.log(i++) // 記得 i++ 會先賦與自身變數後再計算 // 如果這邊放 break 就只會跑一圈。 } console.log('i=', i) 先賦與 1 給變數 i 執行 while(條件) 後看區塊 印出 變數 i 算出 i = i+ 1 印出字串 和經過 i++ 的變數 i 回到 while 直到條件 i 超過 100 --- ## 6. 最常用的大魔王 for lop ### 一般迴圈常見的形式 我們想要特定範圍內的數字或東西,如: 1...100 a...b --- ### do...while... var i = 1 // 初始值; console.log(i) do { console.log(i++) // i 每圈要做的事情 } while(i<=100) { // 終止條件; console.log('i=', i) } // while 的場合: var i = 1 // 初始值; console.log(i) while(i<=100) { // 終止條件; console.log(i++) // i 每圈要做的事情 } console.log('i=', i) 迴圈三要素: 初始值、每圈的 to do list 、 終止條件。 ### 而 for loop 其實是用一個不同的語法來做這三要素 會用在你已經知道有多少圈的情況下,結構如下: for (初始值; 終止條件; i 每圈要做的事情) { // ; 表示這行結束; } --- 先寫結構語法比較不會出錯: for (var i = 1; i<=100; i++) { console.log(i) } // 會跑到 100 停下來。 實際上是這樣跑 ↓ var i = 1 ; 檢查 (i<=100) { 如果條件 i 是 <=100 , 繼續執行迴圈; console.log(i) ; i++ , 即 i+=1 } ; 回到 console.log(i) ; 一直往下跑; 直到檢查 (i<=100) { 如果條件 i 是超過 <=100 } , 終止執行迴圈。 --- ### 如果是為了休息一下 for break 的場合: for (var i = 1; i<=5; i++) { if (i===3) break console.log(i) } // 會只印出 1 2 然後就跳掉。 var i = 1 ; 檢查 { 如果條件 i 是 <=5 , 繼續執行迴圈; if (i嚴格相等3) 終止 console.log(i) ; i++ , 即 i+=1 } ; 回到 console.log(i) ; 一直往下跑; 直到檢查 { 如果條件 i ===3 } , 終止執行迴圈。 ### 如果是為了接關 for continue 的場合: for(var i =1; i<=5; i++) { if (i===3) continue console.log(i) } // 會除了 3 不印出來外,印出 1245 。 var i = 1 ; 檢查 { 如果條件 i 是 <=5 , 繼續執行迴圈; if (i嚴格相等3) 當前的值不要,然後繼續接關執行迴圈; console.log(i) ; i++ , 即 i+=1 } ; 回到 console.log(i) ; 一直往下跑; 直到檢查 { 如果條件 i 的值超過 5 } , 終止執行迴圈。 ### 初始新手教學關可以跳過,但之後的關卡可不能 初始值可以跳過,但還是要寫在外面這樣: var i = 1 for(; i<=10; i++) { if (i%2) continue console.log(i) } // 因為不要奇數,所以印出 246810 。 --- ### 如果搬家請大聲說出想要箱子 可以搭配陣列 [ ] 的用法: var numbers = [1,2,3,4,5] for (var i=0; i<=4; i++) { console.log(numbers[i]) } 因為陣列的起始值,也就是第一位是 0 , 而陣列 [ ] 中只有 5 個數值,因此 i 是設置 4 , 而如果 i<= 5 的情況則會多出一個未定義在陣列的值。 而也可以這樣用: var numbers = [1, 2, 3, 4, 5] for (var i=0; i<5; i++) { console.log(numbers[i]) } // 使用小於 < 的情況,亦或是下式: var numbers = [1, 2, 3, 4, 5] for (var i=0; i<numbers.length; i++) { console.log(numbers[i]) } ### 眾志成城,即是人海優勢 可以應用在總和的算法: var numbers = [1, 2, 3, 4, 5] var sum = 0 for (var i=0; i<numbers.length; i++) { sum += numbers[i] } console.log(sum) ### 大家都是箱子的好朋友 陣列 [ ] 也可以跟 while 混用算出總和: var numbers = [1, 2, 3, 4, 5] var sum = 0 var i = 0 while(i<numbers.length) { sum += numbers[i] i++ } console.log(sum) 迴圈是要一步一步,一行一行檢查~ --- 自己try 這樣會印出五排的陣列: var numbers = [1, 2, 3, 4, 5] var sum = 0 for (var i=0; i<numbers.length; i++) { sum += numbers[i] console.log(numbers) // 會印出陣列內數字 } --- 自己在 try 印出奇數的情況: for (var i = 1; i<=100; i++) { console.log(i) console.log(i<=100) console.log(i++) } console.log('i=', i) 會先給 i 這個值,一開始是 1 ; 判斷 i 是不是 <=100 ; 先賦與自身變數再計算 +1 所以這時候是 2 ; 印出 i 值,一開始是 1 ; 接著判斷條件是 true; 印出 i++ ,因一開始先賦與自身變數所以是 1 ,但由於面有執行到 i++ 值已是 +2 , 而這邊再一個 i++ 所以變成 3 ; 因前一動計算會先給 i 這個值經過兩次 i++ 因此是 3 ; 判斷 i 是不是 <=100 ; 先賦自身變數再計算+1 , 這時為 4 ; 印出上面經過兩次 i++ 的值 3 ; 接著判斷條件是 true; 印出 i++ ,因前一動計算會先給 i ,而 i++ 先賦與自身變數所以 i 是 3 ,但由於面有執行到 i++ 值已是 4 , 而這邊再一個 i++ +1 所以值會成 5 ; 自己在 try 印出偶數的情況: for (var i = 1; i<=100; ++i) { console.log(i) console.log(i<=100) console.log(++i) } console.log('i=', i) 會先給 i 這個值,一開始是 1 ; 判斷 i 是不是 <=100 ; 先計算再賦與自身變數 +1 所以這時候是 2 ; 印出 i 值,一開始是 1 ; 接著判斷條件是 true; 印出 i++ ,因先計算再賦與自身變數所以是 2 ,由於面有執行到 ++i 值已是 +2 , 而這邊再一個 ++i 所以變成+3 ; 因前一動先計算再給 i 這個值經過兩次 ++i 因此是 3 ; 判斷 i 是不是 <=100 ; 先計算再賦與自身變數 +1 , 這時為 4 ; 印出上面經過兩次 ++i 的值 3 ; 接著判斷條件是 true; 印出 ++i ,因前一動先計算再給 i ,而 ++i 先計算再賦與自身變數所以 i 是 4 ,但由於面有執行到 i++ 值已是 5 ;