โครงสร้างการวนซ้ำ
บ่อยครั้งที่ในโปรแกรมเราต้องการให้มีการทำงานอะไรบางอย่างที่ทำซ้ำหลายรอบ
หากการทำซ้ำนั้นมีอะไรบางอย่างที่เหมือนๆเดิม หรือว่าต่างกันไปแค่บางส่วน
แบบนั้นแทนที่จะเขียนโค้ดคล้ายๆเดิมไปซ้ำๆ ควรจะใช้โครงสร้างวนซ้ำในการเขียน
วิธีการเขียนโปรแกรมให้วนซ้ำมีอยู่หลายวิธี ในบทนี้จะแนะนำ ๓
แบบที่เป็นพื้นฐานและนิยมใช้ คือ
แต่ละวิธีสามารถใช้เพื่อทำการวนซ้ำได้เหมือนกัน แต่จะมีรายละเอียดต่างกันไป
นอกจากนี้ยังมีวิธีการอื่นที่ใช้ในการวนซ้ำอีก ซึ่งจะกล่าวถึงต่อไปในบทถัดๆไป
โครงสร้าง while
วิธีการใช้
while (เงื่อนไขที่จะให้ทำซ้ำต่อไป) {
สิ่งที่ต้องการให้ทำซ้ำ
}
วิธีการใส่เงื่อนไขนั้นเหมือนกับใน if คือใส่ค่าที่จะถูกตีความเป็นจริงเท็จได้
ค่าที่ถูกใส่ควรเป็นค่าที่มีความเปลี่ยนแปลงไปในระหว่างวนซ้ำการวนจะเกิดขึ้นซ้ำไปเรื่อยๆตราบใดที่ยังเป็นจริง
และจะหยุดเมื่อเงื่อนไขเป็นเท็จขึ้นมา
ตัวอย่างเช่น ต้องการไล่เรียงเลขคี่ตั้งแต่ 1 ถึง 11 อาจเขียนแบบนี้
var i = 1;
var s = "";
while (i < 12) {
s += i + "~";
i += 2;
}
alert(s); // ได้ 1~3~5~7~9~11~
รอบแรก i จะเท่ากับ 1 ซึ่งน้อยกว่า 12 จึงเริ่มทำคำสั่งไปในรอบแรก แล้ว i
ก็จะเพิ่มเป็น 3 แล้วเข้าสู่รอบใหม่ ตรวจดูเงื่อนไขใหม่ ยังน้อยกว่า 12
อยู่ก็ทำต่อ จากนั้นก็วนซ้ำไปเรื่อยๆ จนในรอบที่ ๖ เมื่อสิ้นสุดรอบ ค่าของ i
กลายเป็น 13 จึงทำให้เงื่อนไข i<12 เป็นเท็จ จึงสิ้นสุดการวนซ้ำ
ระวังการวนซ้ำไม่สิ้นสุด
เมื่อมีการใช้โครงสร้างวนซ้ำ สิ่งที่ต้องระวังอยู่อย่างสม่ำเสมอก็คือ
ต้องไม่ให้เกิดการวนซ้ำอย่างไม่สิ้นสุด หรือที่เรียกว่า
"วังวนอนันต์" (infinite loop)
ยกตัวอย่างเช่น
var a = 0;
var i = 1;
while (i > 0) {
a = a + i++;
}
กรณีนี้ รอบแรก i จะเป็น 1 ถัดมาเป็น 2, 3, 4, ... ไปเรื่อยๆ
ไม่ว่าจะวนซ้ำไปกี่ครั้งเงื่อนไขใน while ก็จะยังคงเป็นจริงตลอด เพราะ i
แต่ละรอบมีแต่จะยิ่งบวกเพิ่ม ไม่มีทางกลับมาน้อยกว่า 0 ได้
จึงเกิดการวนซ้ำตลอดไป
เมื่อเกิดเหตุการณ์แบบนี้ขึ้นจะทำให้เครื่องทำงานหนักอย่างต่อเนื่อง
ให้รีบหาทางหยุดโค้ดโดยเร็ว
ถ้ารันโค้ดนี้โดยการเปิดหน้าเว็บในเบราว์เซอร์ก็ให้รีบปิดหน้านั้นทิ้งไป
การหยุดกลางคันด้วย break
บางครั้งเราอาจต้องการให้หยุดการทำซ้ำเมื่อเข้าเงื่อนไขบางอย่างที่ต้องการ
โดยที่ไม่จำเป็นต้องเข้าเงื่อนไขที่กำหนดไว้ที่ด้านหลัง while
กรณีแบบนี้อาจใส่ if และ break ไว้ในโครงสร้างวนซ้ำ
break เป็นคำสั่งพิเศษที่ถ้าเจอเมื่อไหร่โปรแกรมจะออกจากวังวนทำซ้ำที่ทำอยู่ทันที
โดยทั่วไปจะใช้คู่กับ if เพื่อให้หลุดไปเมื่อเข้าเงื่อนไขที่ต้องการเท่านั้น
ตัวอย่าง
var i = 1;
var s = "";
while (i < 12) {
s += i + "฿";
if (i == 7) break;
i += 2;
}
alert(s); // ได้ 1฿3฿5฿7฿
แบบนี้พอวนซ้ำไปจน i กลายเป็น 7 ก็จะเจอ break แล้วหลุดออกจาก {} ทันที
ไม่ต้องรอให้วนซ้ำจนหมดตามเงื่อนไขของ while
แต่หากไม่เข้าเงื่อนไขที่ทำให้โดน break เสียก่อน ก็วนซ้ำจนจบได้ตามปกติ
var i = 2;
var s = "";
while (i < 12) {
s += i + "฿";
if (i == 7) break;
i += 2;
}
alert(s); // ได้ 2฿4฿6฿8฿10฿
นอกจากนี้ยังอาจเขียนวังวนในลักษณะที่ให้ break เป็นเงื่อนไขแทนใน while ได้
โดยปล่อย while เป็นจริงไปตลอดไป กรณีนี้เงื่อนไขที่ใส่จะตรงกันข้ามกับใส่ while
โดยตรง เพราะจะเลิกวนเมื่อเงื่อนไขเป็นจริง
var i = 4;
var s = "";
while (1) {
if (i > 15) break;
s += i + "ㄣ";
i += 3;
}
alert(s); // ได้ 4ㄣ7ㄣ10ㄣ13ㄣ
การใช้ continue
บางครั้งเราอาจเจอกรณีที่ต้องการให้สิ้นสุดการทำซ้ำในรอบนั้นแล้วข้ามไปรอบต่อไปทันทีเลย
กรณีแบบนี้ให้ใช้ continue
continue ต่างจาก break ตรงที่ break
จะหยุดออกจากโครงสร้างส่วนภายในปีกกาที่วนซ้ำไปเลย แต่ continue
แค่มาเริ่มวนรอบถัดไปต่อทันทีเท่านั้น
ตัวอย่าง
var i = 1;
var s = "";
while (i < 27) {
i += 3;
if (i > 7 && i < 21) continue;
s += i + "ㄐ";
}
alert(s); // ได้ 4ㄐ7ㄐ22ㄐ25ㄐ28ㄐ
แบบนี้เมื่อมีการวน พอค่า i อยู่ระหว่าง 7 ถึง 21 จะถูกข้ามไป ไม่มีการบวก s
เพิ่ม แต่ i ก็ยังคงเพิ่มอยู่ พอถึง 21 ก็กลับมาบวก s ต่อ
ให้ระวังวังวนอนันต์ที่อาจเกิดจาก continue ด้วย เช่นเผลอวาง i++ ไว้หลัง
continue แบบนี้
var i = 1;
var s = "";
while (i < 27) {
if (i > 7 && i < 21) continue;
i += 3;
s += i + "ㄐ";
}
แบบนี้จะทำให้ i ไม่มีการบวกเพราะเจอ continue แล้วก็จะวนซ้ำไม่สิ้นสุด
วังวนซ้อน
สามารถสร้างโครงสร้างการวนซ้ำให้ซ้อนกันได้ เช่นซ้อนสองชั้นจะกลายเป็นแบบนี้
s = "";
var i = 1;
while (i < 5) { // เริ่ม while วงนอก
var j = 1;
while (j < 4) { // เริ่ม while วงใน
s += "¡" + j + i;
j++;
} // สิ้นสุด while วงใน
s += "ㄓ";
i++;
} // สิ้นสุด while วงนอก
alert(s); // ได้ ¡11¡21¡31ㄓ¡12¡22¡32ㄓ¡13¡23¡33ㄓ¡14¡24¡34ㄓ
แบบนี้ในแต่ละรอบที่มีการวนซ้ำโดย while ด้านนอก ค่า i จะเปลี่ยนไปเรื่อยๆ
ภายในแต่ละรอบนั้นจะมีการวนซ้ำด้วย while ด้านในซึ่งมีการเปลี่ยนค่า j
ไปเรื่อยๆหลายครั้ง
โดยทั่วไปเมื่อเขียนโครงสร้างซ้อนจะมีการเคาะวรรคให้ร่นเข้าไปตามลำดับขั้นเพื่อให้เข้าใจได้ง่ายว่าตรงไหนอยู่ในวงในหรือวงนอก
โครงสร้าง while อาจจะซ้อนกี่ชั้นก็ได้ หลักการเหมือนกัน เช่น
ซ้อนสามชั้นอาจเขียนได้แบบนี้
s = "";
var i = 1;
while (i < 5) { // เริ่ม while วงนอกสุด
var j = 1;
while (j < 4) { // เริ่ม while วงกลาง
var k = 1;
while (k < 3) { // เริ่ม while วงในสุด
s += "≈" + k + j + i;
k++;
} // สิ้นสุด while วงในสุด
s += " × ";
j++;
} // สิ้นสุด while วงกลาง
s += "\n";
i++;
} // สิ้นสุด while วงนอกสุด
alert(s);
ได้
≈111≈211 × ≈121≈221 × ≈131≈231 ×
≈112≈212 × ≈122≈222 × ≈132≈232 ×
≈113≈213 × ≈123≈223 × ≈133≈233 ×
≈114≈214 × ≈124≈224 × ≈134≈234 ×
โครงสร้าง do while
นอกจากโครงสร้างวนซ้ำโดยใช้ while เฉยๆแล้ว ยังมีอีกรูปแบบที่ดูแล้วใกล้เคียงกัน
คือ do๛while
ลักษณะจะคล้ายกับ while เปล่าๆ แต่ว่าจะขึ้นต้นด้วย do แล้วปิดท้ายด้วย while
โครงสร้างเป็นแบบนี้
do {
ส่วนที่ต้องการให้ทำซ้ำ;
} while (เงื่อนไขที่ให้ทำซ้ำต่อ);
ตัวอย่าง
var s = "";
var i = 0;
do {
s += "|" + i + "|";
i++;
} while (i < 9);
alert(s); // ได้ |0||1||2||3||4||5||6||7||8|
ที่แตกต่างก็คือ do๛while จะมีการทำรอบแรกก่อนแล้วค่อยดูเงื่อนไข
ดังนั้นจึงมีการทำอย่างน้อยหนึ่งรอบแน่นอน แต่ while
นั้นถ้าไม่เข้าเงื่อนไขตั้งแต่แรกก็จะไม่มีการทำเลยแม้แต่รอบเดียว
โครงสร้าง for
for เป็นโครงสร้างสำหรับวนซ้ำอีกแบบที่นิยมใช้กัน
วิธีการใช้คล้ายกับ while
แต่สามารถเขียนได้สั้นกว่าเหมาะสำหรับเวลาที่มีตัวแปรตัวเดียวเป็นเงื่อนไขในการหยุด
และตัวแปรนั้นมีการเปลี่ยนแปลงแบบแน่นอน
โครงสร้างในการใช้
for (var ค่าเริ่มต้นของตัวแปร; เงื่อนไขการให้วนซ้ำ; ความเปลี่ยนแปลงในแต่ละรอบ) {
ส่วนที่ต้องการให้ทำซ้ำ;
}
ตัวอย่าง
var s = "";
for (var i = 1; i < 41; i += 5) {
s += i + "#";
}
alert(s); // ได้ 1#6#11#16#21#26#31#36#
การที่รวม ๓ สิ่งไว้ในวงเล็บหลัง for ทั้งหมดทำให้เขียนได้สั้นกว่าการใช้ while
แม้ว่าอาจดูแล้วเข้าใจยากกว่าสักหน่อย สำหรับผู้เริ่มฝึกหัด
สำหรับคนที่ใช้ภาษาอื่นด้วยมีช้อควรระวังเล็กน้อย คือแต่ละภาษาใช้คำสั่ง for
ในความหมายต่างกันไป ความหมายของ for ในจาวาสคริปต์จะคล้ายกับ for
ในบางภาษาเช่นภาษาซี แต่จะต่างจาก for ในบางภาษาเช่นไพธอนหรือรูบี
จึงต้องระวังสับสน
นอกจากนี้ในจาวาสคริปต์ยังมีโครงสร้าง for ๛ in คือใช้ for ร่วมกับ in
ซึ่งก็มีความหมายต่างไปจากการใช้ for เดี่ยวๆอีก และก็ต่างจาก for ๛ in
ในไพธอนหรือรูบีด้วย จึงยิ่งสับสนได้ง่าย
เรื่องของ for ๛ in จะเขียนถึงใน
บทที่ ๒๓
และใน ES6 ยังมีโครงสร้าง for ๛ of เพิ่มเข้ามาอีก ซึ่งจะไปเขียนถึงในเนื้อหาส่วน
ES6