Day 12 同樣因為Tutorial的迴圈(loop)觀念跟JavaScript是相同的,所以只會回顧迴圈的重點。
迴圈(loop)代表的是重複做相同或類似的事情好幾次。而在JavaScript裡,迴圈可以先分為兩種類型:一種是知道明確的迴圈次數時可以使用 for
迴圈,另一種是達到指定條件時則可按情境使用 while
或 do-while
迴圈。
先來複習 for
迴圈。基本上就是當明確地知道待執行事項的重複次數時,可以優先選擇使用 for
迴圈。
for
迴圈的基本語法如下:
for(初始值; 判斷條件; 運算式){
// 執行事項
}
例如想要列出一個陣列包含的所有元素,因為陣列的長度是可以事先預知的,所以:
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8];
for(let i=0; i < arr.length; ++i){
console.log(arr[i]);
}
初始值是在執行迴圈以前就會宣告好的迴圈計數器,例如 let i = 0
;判斷條件是當每一次迴圈結束時會執行的判斷,如果判斷結果為true就會繼續迴圈區塊裡的程式碼,例如每次迴圈結束就會檢查 i
是否小於 arr.length
,而運算式則是會在每次迴圈結束、判斷以前更新目前的計數器。
所以每次迴圈結束以後的流程應該是:運算式++i
會讓 i
先增加1,接著會檢查 i < arr.length
,如果檢查結果為 true
就會執行 console.log(arr[i])
這段。
雖然 for
迴圈的基本語法是長這樣,事實上 for
迴圈的初始值、判斷條件和運算式都是能夠拿掉的,比如:
for(;;){
// 執行事項
}
不過這樣就會形成無限迴圈(infinite loop),所以應該要在執行事項裡加上一些判斷來跳出迴圈:
for(;;){
// 執行事項
if(判斷 === true){
break; // 跳出迴圈
}
}
而 for
迴圈也是能夠視情況任意拿掉初始值、判斷條件和運算式三者其一,例如初始值要使用迴圈以外的變數:
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8];
let index = 0;
for(; index < arr.length; ++index){
console.log(arr[i]);
}
不過如果是要拿掉判斷式或運算式,應該要將自行定義的判斷式或運算式寫在迴圈區塊裡,確保每次迴圈都會進行判斷或運算,例如:
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8];
for(let i=0; ; ){
if(i < arr.length){
console.log(arr[i]);
}
++i;
}
while
和 do-while
基本上都是以條件來判斷是否繼續執行某件事情的迴圈類型。不一樣的是,while
是屬於先判斷的前測迴圈(pretest);而 do-while
則是屬於後判斷的後測迴圈(post-test),意即先執行一次迴圈區塊裡的程式碼,再判斷是否執行下一次:
// while
const max_limit = 10;
let i = 9;
while(i < 10) {
console.log(i);
++i;
}
// 結果
9
// do-while
const max_limit = 10;
let i = 9;
do {
console.log(i);
++i;
} while(i < 10);
// 結果
9
乍看之下 while
和 do-while
好像沒什麼差別,但在應用上某些時候就適合先執行再判斷,例如「給使用者登入帳號密碼」的情境就適合後判斷:
const account = {
user: abc,
password: '123'
}
let input = '';
do {
input = prompt('請輸入密碼,輸入錯誤達五次就會鎖帳號');
} while (account['password'] !== input && input !== '');
這個情境事實上也是可以用 while
來達成,只是 while
會變成在使用者輸入密碼之前,就得先判斷一次使用者輸入的密碼是否正確:
const account = {
user: abc,
password: '123'
}
let input = '0000000000';
while (account['password'] !== input && input !== '') {
input = prompt('請輸入密碼,輸入錯誤達五次就會鎖帳號');
}
以上範例的 input 有限制使用者必須輸入東西才能判斷,那麼 while
就必須先隨便打一個應該不會符合使用者密碼的字串才能讓使用者輸入密碼,就現實層面而言應該不能發生這樣的事情。
JavaScript還有兩個比較特別的迴圈類型,分別是 for-in
和 for-of
。
for-in
迴圈是可以用來走訪物件,並取得物件鍵值(key)或屬性(property):
let person = {
user: "Alice",
age: 25,
occupation: 'teacher',
isMarried: false,
}
for(let key in person){
console.log(key);
}
// 結果
user
age
occupation
isMarried
不過要注意的是,for-in
只能列出可列舉、非symbol型別的屬性(enumerable, non-symbol properties),有關「enumerable property」的解釋可參考MDN的說明。
for-of
迴圈則是可以用來走訪可迭代物件(iterable object)的值(value):
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8];
for(let value of arr){
console.log(value);
}
// 結果
0
1
2
3
4
5
6
7
8
JavaScript內建的可迭代物件只有 Array
、String
、TypedArray
、Map
、Set
、NodeList
,所以一般的物件不能用for-of
來走訪:
let person = {
user: "Alice",
age: 25,
occupation: 'teacher',
isMarried: false,
}
for(let value of person){
console.log(value); // error, person is not iterable
}
參考資料
TypeScript Turtorial
The Modern JavaScript Tutorial
for...in
Enumerability and ownership of properties
for...of