Article · programming
JavaScript: การทำซ้ำด้วยลูป
JavaScript
EP6 ของชุด JavaScript คืออะไร? เริ่มต้นเขียนโปรแกรม เรียนรู้ for, while, do...while, break, continue และการวนซ้ำข้อมูลด้วยลูปอย่างถูกต้อง
EP6: ทำงานซ้ำอัตโนมัติด้วยลูป
ลองจินตนาการว่าคุณต้องแสดงรายชื่อสินค้า 100 รายการ หากเขียนคำสั่งแสดงผลทีละรายการ คุณจะต้องเขียนโค้ดจำนวนมากและแก้ไขได้ยาก JavaScript มีเครื่องมือที่เรียกว่า **ลูป (Loop)** สำหรับสั่งให้โปรแกรมทำงานเดิมซ้ำตามจำนวนครั้งหรือเงื่อนไขที่กำหนด ช่วยลดโค้ดซ้ำซ้อนและทำให้จัดการข้อมูลจำนวนมากได้สะดวกขึ้น
1. for loop: วนซ้ำตามจำนวนรอบ
คำสั่ง `for` เหมาะกับงานที่ทราบจำนวนรอบหรือสามารถกำหนดจุดเริ่มต้น จุดสิ้นสุด และการเปลี่ยนแปลงค่าตัวนับได้ โครงสร้างทั่วไปประกอบด้วยสามส่วน ได้แก่ การกำหนดค่าเริ่มต้น เงื่อนไขที่ต้องเป็นจริงเพื่อทำงานต่อ และคำสั่งเปลี่ยนค่าหลังจบแต่ละรอบ
for (let i = 1; i <= 5; i++) {
console.log(`รอบที่ ${i}`);
}
// ผลลัพธ์:
// รอบที่ 1
// รอบที่ 2
// รอบที่ 3
// รอบที่ 4
// รอบที่ 5
ในตัวอย่าง `let i = 1` กำหนดค่าเริ่มต้นให้ตัวนับ `i` เท่ากับ 1 ส่วน `i <= 5` เป็นเงื่อนไขให้ทำงานต่อเมื่อค่าน้อยกว่าหรือเท่ากับ 5 และ `i++` เพิ่มค่า `i` ขึ้นหนึ่งหลังจบแต่ละรอบ เมื่อ `i` เพิ่มเป็น 6 เงื่อนไขจะเป็นเท็จและลูปจะหยุดทำงาน
จำโครงสร้าง for ให้ได้`for (ค่าเริ่มต้น; เงื่อนไข; การเปลี่ยนค่า)` ทั้งสามส่วนคั่นด้วยเครื่องหมายอัฒภาค `;` และสามารถปรับให้เหมาะกับโจทย์ได้
2. while loop: วนซ้ำตราบใดที่เงื่อนไขเป็นจริง
คำสั่ง `while` ใช้เมื่อเราต้องการให้โปรแกรมทำงานซ้ำโดยขึ้นอยู่กับเงื่อนไข เงื่อนไขจะถูกตรวจสอบก่อนเริ่มแต่ละรอบ หากเป็นเท็จตั้งแต่แรก คำสั่งภายในลูปจะไม่ทำงานเลย
let count = 1;
while (count <= 3) {
console.log(`กำลังประมวลผลครั้งที่ ${count}`);
count++;
}
console.log('ประมวลผลเสร็จแล้ว');
// ผลลัพธ์:
// กำลังประมวลผลครั้งที่ 1
// กำลังประมวลผลครั้งที่ 2
// กำลังประมวลผลครั้งที่ 3
// ประมวลผลเสร็จแล้ว
จุดสำคัญคือ `count++` ทำให้ตัวแปรเปลี่ยนค่า หากลืมเพิ่มค่าหรือปรับเงื่อนไขให้มีโอกาสเป็นเท็จ ลูปอาจทำงานไม่สิ้นสุด เรียกว่า Infinite Loop ซึ่งอาจทำให้โปรแกรมค้างหรือใช้ทรัพยากรมากเกินไป
3. do...while: ทำงานอย่างน้อยหนึ่งครั้ง
`do...while` แตกต่างจาก `while` ตรงที่โปรแกรมจะทำงานในบล็อกคำสั่งก่อน แล้วจึงตรวจสอบเงื่อนไข ดังนั้นคำสั่งภายในลูปจะทำงานอย่างน้อยหนึ่งครั้ง แม้เงื่อนไขเริ่มต้นจะเป็นเท็จก็ตาม
let number = 10;
do {
console.log(`ค่าปัจจุบันคือ ${number}`);
number++;
} while (number < 5);
// ผลลัพธ์:
// ค่าปัจจุบันคือ 10
เลือกใช้ให้ตรงงานใช้ `for` เมื่อจำนวนรอบชัดเจน ใช้ `while` เมื่อต้องตรวจสอบเงื่อนไขก่อนเริ่มแต่ละรอบ และใช้ `do...while` เมื่อต้องการให้ทำงานอย่างน้อยหนึ่งครั้งก่อนตรวจสอบเงื่อนไข
4. เปรียบเทียบลูปทั้งสามชนิด
| ประเภท | ตรวจสอบเงื่อนไข | จำนวนรอบขั้นต่ำ | ตัวอย่างการใช้งาน |
|---|---|---|---|
| for | ก่อนเริ่มแต่ละรอบ | 0 | แสดงข้อมูล 10 รายการ |
| while | ก่อนเริ่มแต่ละรอบ | 0 | ทำงานตราบใดที่ยังมีงานค้าง |
| do...while | หลังทำงานแต่ละรอบ | 1 | แสดงเมนูอย่างน้อยหนึ่งครั้ง |
5. break: หยุดลูปทันที
บางครั้งเราไม่จำเป็นต้องวนซ้ำจนจบทุกครั้ง เช่น ค้นหาสินค้าที่ตรงกับรหัสที่ต้องการ เมื่อพบแล้วสามารถใช้ `break` เพื่อออกจากลูปได้ทันที ช่วยลดการทำงานที่ไม่จำเป็น
const productIds = [101, 205, 308, 412, 509];
const targetId = 308;
let found = false;
for (const id of productIds) {
console.log(`ตรวจสอบสินค้า ${id}`);
if (id === targetId) {
found = true;
console.log('พบสินค้าที่ต้องการ');
break;
}
}
console.log(`ผลการค้นหา: ${found ? 'พบ' : 'ไม่พบ'}`);
// ผลลัพธ์บางส่วน:
// ตรวจสอบสินค้า 101
// ตรวจสอบสินค้า 205
// ตรวจสอบสินค้า 308
// พบสินค้าที่ต้องการ
// ผลการค้นหา: พบ
เมื่อพบรหัส 308 ลูปจะหยุดทันที จึงไม่ตรวจสอบรหัส 412 และ 509 ต่อไป การใช้ `break` มีประโยชน์กับงานค้นหาและการหยุดประมวลผลเมื่อพบเงื่อนไขที่ต้องการ
6. continue: ข้ามรอบปัจจุบัน
คำสั่ง `continue` ไม่ได้หยุดลูปทั้งหมด แต่จะข้ามคำสั่งที่เหลือในรอบปัจจุบัน แล้วไปเริ่มรอบถัดไป เหมาะกับการกรองข้อมูลที่ไม่ต้องการประมวลผล
for (let i = 1; i <= 5; i++) {
if (i === 3) {
continue;
}
console.log(i);
}
// ผลลัพธ์:
// 1
// 2
// 4
// 5
อย่าสับสนระหว่าง break กับ continue`break` ออกจากลูปทั้งหมดที่กำลังทำงานอยู่ ส่วน `continue` ข้ามเฉพาะรอบปัจจุบันแล้วไปยังรอบถัดไป สำหรับ `for` คำสั่งเปลี่ยนค่าตัวนับยังทำงานตามปกติก่อนเริ่มรอบถัดไป
7. วนซ้ำสมาชิกใน Array ด้วย for...of
เมื่อมีข้อมูลหลายรายการเก็บอยู่ใน Array เราสามารถใช้ `for...of` เพื่ออ่านค่าของแต่ละสมาชิกได้โดยตรง ไม่จำเป็นต้องจัดการตัวนับหรือเขียนเงื่อนไขตรวจสอบตำแหน่งด้วยตนเอง
const products = [
'คีย์บอร์ด',
'เมาส์',
'จอภาพ'
];
for (const product of products) {
console.log(`สินค้า: ${product}`);
}
// ผลลัพธ์:
// สินค้า: คีย์บอร์ด
// สินค้า: เมาส์
// สินค้า: จอภาพ
ตัวแปร `product` จะได้รับค่าแต่ละรายการใน Array ตามลำดับ การใช้ `const` ในตัวแปรของลูปทำได้ เพราะแต่ละรอบจะมีการกำหนดค่าของตัวแปรใหม่ภายในขอบเขตของรอบนั้น เหมาะสำหรับการอ่านข้อมูลที่ไม่ต้องแก้ไขตัวแปรอ้างอิงในแต่ละรอบ
8. วนซ้ำข้อมูลแบบ key-value ด้วย for...in
คำสั่ง `for...in` ใช้วนซ้ำชื่อคุณสมบัติหรือคีย์ที่แจกแจงได้ของออบเจ็กต์ (Object) จึงเหมาะกับการอ่านข้อมูลที่มีชื่อฟิลด์ เช่น ชื่อสินค้า ราคา และจำนวนคงเหลือ หากต้องการอ่านสมาชิกของ Array ตามลำดับ โดยทั่วไปควรเลือก `for...of` แทน
const product = {
name: 'Mechanical Keyboard',
price: 1590,
stock: 12
};
for (const key in product) {
console.log(`${key}: ${product[key]}`);
}
// ผลลัพธ์:
// name: Mechanical Keyboard
// price: 1590
// stock: 12
แนวทางเลือกใช้`for...of` ใช้อ่านค่าจากข้อมูลที่วนซ้ำได้ เช่น Array ส่วน `for...in` ใช้อ่านชื่อคีย์ของ Object โดยตรง ทั้งสองคำสั่งมีหน้าที่ต่างกันและไม่ควรใช้แทนกันโดยไม่พิจารณาโครงสร้างข้อมูล
9. ตัวอย่างจริง: คำนวณยอดขายจากรายการสินค้า
ระบบร้านค้าอาจต้องรวมยอดขายจากสินค้าแต่ละรายการ ลูปช่วยให้คำนวณยอดรวมได้โดยไม่ต้องเขียนคำสั่งบวกทีละรายการ ตัวอย่างนี้ใช้ `for...of` อ่านข้อมูลสินค้า คูณราคากับจำนวนขาย แล้วสะสมยอดรวม
const sales = [
{ name: 'Keyboard', price: 1200, quantity: 2 },
{ name: 'Mouse', price: 450, quantity: 3 },
{ name: 'Monitor', price: 5200, quantity: 1 }
];
let totalRevenue = 0;
let totalItems = 0;
for (const item of sales) {
const subtotal = item.price * item.quantity;
totalRevenue += subtotal;
totalItems += item.quantity;
console.log(`${item.name}: ${subtotal} บาท`);
}
console.log(`จำนวนสินค้ารวม: ${totalItems} ชิ้น`);
console.log(`ยอดขายรวม: ${totalRevenue} บาท`);
// ผลลัพธ์:
// Keyboard: 2400 บาท
// Mouse: 1350 บาท
// Monitor: 5200 บาท
// จำนวนสินค้ารวม: 6 ชิ้น
// ยอดขายรวม: 8950 บาท
ในตัวอย่างนี้ `totalRevenue += subtotal` เป็นการนำยอดของรายการปัจจุบันไปบวกเพิ่มในยอดรวมเดิม ส่วน `totalItems += item.quantity` ใช้รวมจำนวนสินค้าทั้งหมด วิธีนี้นำไปต่อยอดกับระบบ POS รายงานยอดขาย และการสรุปข้อมูลจากฐานข้อมูลได้
10. การวิเคราะห์จำนวนรอบและประสิทธิภาพ
ก่อนเขียนลูปควรพิจารณาว่าต้องทำงานกี่ครั้ง และในแต่ละรอบต้องประมวลผลอะไรบ้าง หากลูปทำงานทั้งหมด n รอบและแต่ละรอบใช้เวลาคงที่โดยประมาณ เวลาทำงานโดยรวมมักเพิ่มขึ้นตามจำนวนรอบ ซึ่งมักอธิบายด้วยสัญลักษณ์ Big O เป็น $O(n)$
จำนวนรอบของลูปแบบเพิ่มทีละหนึ่ง
i = 1,2,3,\ldots,nเมื่อตัวนับเริ่มจาก 1 และเพิ่มทีละหนึ่งจนถึง n จะเกิดการทำงาน n รอบ หากไม่มีคำสั่งที่เปลี่ยนแปลงเส้นทางการทำงาน
const n = 5;
let iterations = 0;
for (let i = 1; i <= n; i++) {
iterations++;
}
console.log(`จำนวนรอบทั้งหมด: ${iterations}`);
// ผลลัพธ์: จำนวนรอบทั้งหมด: 5
การเพิ่มจำนวนรอบเป็นสองเท่าอาจทำให้เวลาทำงานเพิ่มขึ้นใกล้เคียงสองเท่าในลูปที่มีต้นทุนต่อรอบคงที่ แต่เวลาจริงยังขึ้นอยู่กับงานภายในลูป ฮาร์ดแวร์ และสภาพแวดล้อมการทำงานด้วย ลูปซ้อนลูปอาจเพิ่มจำนวนการประมวลผลอย่างรวดเร็ว จึงควรหลีกเลี่ยงงานซ้ำที่ไม่จำเป็น
| Label | จำนวนรอบ |
|---|---|
| 10 รายการ | 10 |
| 20 รายการ | 20 |
| 30 รายการ | 30 |
| 40 รายการ | 40 |
| 50 รายการ | 50 |
11. ข้อผิดพลาดที่พบบ่อยในการใช้ลูป
| ปัญหา | สาเหตุ | แนวทางแก้ไข |
|---|---|---|
| ลูปทำงานไม่หยุด | เงื่อนไขไม่มีวันเป็นเท็จหรือค่าตัวนับไม่เปลี่ยน | ตรวจสอบเงื่อนไขและการเปลี่ยนค่าทุกครั้ง |
| ทำงานเกินจำนวนรอบ | ใช้ < หรือ <= ไม่ตรงกับขอบเขตที่ต้องการ | กำหนดจุดเริ่มต้นและจุดสิ้นสุดให้ชัดเจน |
| ข้ามข้อมูลรายการสุดท้าย | ใช้เงื่อนไขที่หยุดก่อนถึงตำแหน่งสุดท้าย | ตรวจสอบขอบเขต Array และค่า index |
| แก้ไขข้อมูลระหว่างวนซ้ำแล้วเกิดผลผิด | เปลี่ยนแปลง Array หรือ Object ระหว่างประมวลผล | กำหนดกติกาการแก้ไขข้อมูลและลำดับการทำงานให้ชัดเจน |
| ใช้ for...in กับ Array โดยไม่จำเป็น | เข้าใจว่า key และ value เป็นสิ่งเดียวกัน | ใช้ for...of เมื่อต้องการอ่านค่าของสมาชิก |
12. แบบฝึกหัดท้ายบท
ฝึกเขียนโปรแกรมโดยใช้ลูปเพื่อแสดงเลขคู่ตั้งแต่ 2 ถึง 20 จากนั้นคำนวณผลรวมของตัวเลขตั้งแต่ 1 ถึง 100 และสร้างลูปสำหรับค้นหารหัสสินค้า 999 ใน Array ที่กำหนดไว้ เมื่อพบรหัสแล้วให้หยุดลูปด้วย `break` พยายามเขียนด้วยตนเองก่อนเปิดดูตัวอย่างเฉลย
เฉลยข้อ 1: แสดงเลขคู่ 2 ถึง 20
ใช้ for โดยเริ่ม i ที่ 2 กำหนดเงื่อนไข i <= 20 และเพิ่ม i ทีละ 2 ด้วย i += 2 ผลลัพธ์คือ 2, 4, 6, 8, 10, 12, 14, 16, 18 และ 20
เฉลยข้อ 2: ผลรวมตั้งแต่ 1 ถึง 100
กำหนด let sum = 0 แล้ววน for ตั้งแต่ i = 1 ถึง i <= 100 โดยเพิ่ม sum ด้วย sum += i เมื่อจบลูปจะได้ผลรวม 5050
เฉลยข้อ 3: ค้นหาสินค้าด้วย break
วนสมาชิกใน Array ด้วย for...of แล้วตรวจสอบ if (id === 999) หากเป็นจริงให้แสดงข้อความว่าพบสินค้าและเรียก break เพื่อออกจากลูป หากวนครบแล้วยังไม่พบ ควรแยกสถานะการค้นหาไว้ในตัวแปรเพื่อแสดงผลว่าไม่พบข้อมูล
13. สรุปและเตรียมพร้อมสำหรับ EP7
ลูปเป็นพื้นฐานสำคัญที่ช่วยให้โปรแกรมทำงานกับข้อมูลหลายรายการได้อย่างมีประสิทธิภาพ `for` เหมาะกับการวนซ้ำที่กำหนดจำนวนรอบได้ `while` ตรวจสอบเงื่อนไขก่อนเริ่มแต่ละรอบ และ `do...while` ทำงานก่อนตรวจสอบเงื่อนไข ส่วน `break` ใช้หยุดลูป `continue` ใช้ข้ามรอบปัจจุบัน และ `for...of` กับ `for...in` ช่วยอ่านข้อมูลตามโครงสร้างที่เหมาะสม เมื่อเข้าใจลูปแล้ว ขั้นต่อไปคือการจัดเก็บข้อมูลหลายรายการอย่างเป็นระบบด้วย Array และการใช้เมธอดสำคัญในการจัดการข้อมูล
การเขียนโค้ดให้ทำงานซ้ำอย่างถูกต้อง คือการเปลี่ยนงานจำนวนมากให้กลายเป็นขั้นตอนเล็ก ๆ ที่ควบคุมได้
บทถัดไป: Array และการจัดการชุดข้อมูลEP7 จะพาคุณเรียนรู้การสร้าง Array การเข้าถึงสมาชิก การเพิ่มและลบข้อมูล รวมถึงการใช้เมธอดอย่าง map, filter และ find เพื่อประมวลผลข้อมูลด้วย JavaScript
อ่านจนถึงระยะ 500px ก่อนท้ายหน้าและอยู่ในหน้านี้อย่างน้อย 5 นาที เพื่อรับ EXP วันละครั้ง
⏳ กำลังจับเวลาอ่าน...