แนวปฏิบัติที่ดีที่สุดสำหรับการใช้ลูป for ใน TypeScript

แนวปฏิบัติที่ดีที่สุดสำหรับการใช้ลูป for ใน TypeScript

บทความนี้อธิบายแนวปฏิบัติที่ดีที่สุดสำหรับการใช้ลูป for ใน TypeScript

YouTube Video

แนวปฏิบัติที่ดีที่สุดสำหรับการใช้ลูป for ใน TypeScript

คำสั่ง for เป็นไวยากรณ์สำคัญและทรงพลังสำหรับการดำเนินการที่ซ้ำ ๆ ใน TypeScript การใช้ประโยชน์จากความปลอดภัยของชนิดข้อมูล (type safety) และการเขียนโค้ดที่เน้นความง่ายในการอ่านและบำรุงรักษา ช่วยให้คุณเขียนโค้ดได้อย่างมีประสิทธิภาพและมีข้อผิดพลาดน้อยลง

การเลือกประเภทลูปที่เหมาะสม

TypeScript มีโครงสร้างลูปหลากหลายประเภท ซึ่งเหมาะสำหรับกรณีการใช้งานที่แตกต่างกัน การเลือกใช้ลูปที่เหมาะสมเป็นสิ่งสำคัญต่อความชัดเจนและประสิทธิภาพของโค้ด

ลูป for มาตรฐาน

1for (let i = 0; i < 10; i++) {
2    console.log(i);
3}

for loop แบบมาตรฐานเหมาะสมเมื่อคุณต้องการควบคุมดัชนีของการวนลูปอย่างแม่นยำ

แนวทางปฏิบัติที่ดีที่สุด
1const maxIterations = 10;
2for (let i = 0; i < maxIterations; i++) {
3    console.log(i);
4}

เมื่อเขียนคำสั่ง for ให้พิจารณาประเด็นต่อไปนี้เพื่อช่วยให้คุณเขียนโค้ดที่ปลอดภัยและอ่านง่ายยิ่งขึ้น

  • ใช้ let สำหรับตัวแปรดัชนี
    • การใช้ let แทน var จะจำกัดขอบเขตการใช้งานเพียงในบล็อกนั้น ซึ่งช่วยป้องกันพฤติกรรมที่ไม่คาดคิด
  • ใช้ค่าคงที่และชื่อตัวแปรที่สื่อความหมายชัดเจน เพื่อทำให้ขอบเขตของลูปชัดเจนยิ่งขึ้น
    • หลีกเลี่ยงการใช้ตัวเลขไร้บริบท (magic numbers) และใช้ชื่อตัวแปรที่มีความหมายเพื่อเพิ่มความง่ายในการอ่าน

ลูป for...of

1const array = [1, 2, 3];
2for (let value of array) {
3    console.log(value);
4}

ลูป for...of เหมาะสำหรับการวนซ้ำบนออบเจ็กต์ที่สามารถวนซ้ำได้ เช่น อาร์เรย์และสตริง

แนวทางปฏิบัติที่ดีที่สุด
1const array = [1, 2, 3];
2for (const value of array) {
3    console.log(value);
4}

เมื่อเขียนลูป for...of การพิจารณาประเด็นต่อไปนี้จะช่วยให้คุณเขียนโค้ดได้อย่างปลอดภัยยิ่งขึ้น

  • ใช้ const สำหรับตัวแปรในลูป
    • หากค่าภายในลูปไม่ได้ถูกเปลี่ยนแปลง การใช้ const จะช่วยป้องกันการกำหนดค่าใหม่โดยไม่ตั้งใจ

ลูป for...in

1const obj = { a: 1, b: 2, c: 3 };
2for (const key in obj) {
3    console.log(`${key}: ${obj[key]}`);
4}

ลูป for...in ใช้สำหรับวนซ้ำเหนือสมบัติที่สามารถนับได้ของออบเจ็กต์

แนวทางปฏิบัติที่ดีที่สุด
1const obj = { a: 1, b: 2, c: 3 };
2for (const key in obj) {
3    if (obj.hasOwnProperty(key)) {
4        console.log(`${key}: ${obj[key]}`);
5    }
6}

เมื่อเขียนลูป for...in คุณสามารถพิจารณาประเด็นต่อไปนี้

  • กรองคุณสมบัติ
    • หากคุณต้องการหลีกเลี่ยงพร็อพเพอร์ตี้ที่ถูกสืบทอดมา คุณสามารถใช้ hasOwnProperty
  • อย่าใช้ for...in กับอาร์เรย์ หลีกเลี่ยงการใช้ for...in กับอาร์เรย์ มันอาจวนลูปผ่านคุณสมบัติที่สามารถนับได้ทั้งหมด รวมถึงคุณสมบัติที่ไม่ใช่ดัชนีของอาร์เรย์

วิธีการ forEach

1const array = [1, 2, 3];
2array.forEach((value, index) => {
3    console.log(`Index: ${index}, Value: ${value}`);
4});

เมื่อวนซ้ำบนอาร์เรย์ การใช้ forEach กระชับและช่วยลดความยุ่งยากในการจัดการดัชนี

แนวทางปฏิบัติที่ดีที่สุด

เมื่อใช้เมธอด forEach คุณสามารถพิจารณาประเด็นต่อไปนี้

  • ใช้ฟังก์ชันลูกศร
    • ใช้ฟังก์ชันลูกศรที่ย่อเพื่อเพิ่มความเข้าใจง่าย
  • หลีกเลี่ยงการหยุดชะงัก
    • forEach ไม่รองรับ break หรือ continue ใช้ลูป for...of หรือ for เมื่อจำเป็น:

ความปลอดภัยของชนิดและการป้องกันข้อผิดพลาด

ด้วยการใช้ประโยชน์จากระบบชนิดของ TypeScript คุณสามารถป้องกันข้อผิดพลาดในขณะดำเนินการลูปได้:

กำหนดประเภทอย่างเคร่งครัดสำหรับตัวแปรในลูป

1const items = [1, 2, 3];
2items.forEach(item => {
3    console.log(item * 2);
4});
1const items: number[] = [1, 2, 3];
2items.forEach((item: number) => {
3    console.log(item * 2);
4});

โดยการกำหนดชนิดข้อมูลสำหรับตัวแปรภายในลูปอย่างชัดเจน คุณสามารถตรวจพบข้อผิดพลาดของชนิดข้อมูลได้ตั้งแต่เนิ่น ๆ

หลีกเลี่ยงการใช้ any โดยไม่ได้ตั้งใจ

1{
2  "compilerOptions": {
3    "noImplicitAny": true
4  }
5}

นอกจากนี้ การเปิดใช้งาน noImplicitAny ใน tsconfig.json จะช่วยป้องกันไม่ให้ตัวแปรที่ไม่ได้กำหนดชนิดอย่างชัดเจนถูกกำหนดค่าโดยปริยายเป็นชนิด any

ใช้ ReadonlyArray เมื่อจำเป็น

1const numbers: ReadonlyArray<number> = [1, 2, 3];
2for (const value of numbers) {
3    console.log(value);
4}

หากคุณกำลังวนลูปในอาร์เรย์ที่ไม่ควรถูกแก้ไข คุณสามารถใช้ ReadonlyArray

ข้อพิจารณาด้านประสิทธิภาพ

ประสิทธิภาพเป็นสิ่งสำคัญสำหรับลูปที่ประมวลผลชุดข้อมูลขนาดใหญ่หรือที่ดำเนินการบ่อยครั้ง:

เลือกวิธีการใช้งานลูปที่เหมาะสมที่สุด

มีวิธีการที่หลากหลายในการเขียนลูป และแต่ละวิธีมีความแตกต่างในด้านความอ่านง่ายและประสิทธิภาพในการดำเนินการ

 1// Prepare input data (an array from 1 to 1000000)
 2const input: number[] = Array.from({ length: 1000000 }, (_, i) => i + 1);
 3
 4// --- for ---
 5console.time('for loop');
 6const squaresFor: number[] = [];
 7for (let i = 0; i < input.length; i++) {
 8    squaresFor.push(input[i] * input[i]);
 9}
10console.timeEnd('for loop');
11
12// --- while ---
13console.time('while loop');
14const squaresWhile: number[] = [];
15let i: number = 0;
16while (i < input.length) {
17    squaresWhile.push(input[i] * input[i]);
18    i++;
19}
20console.timeEnd('while loop');
21
22// --- for-of ---
23console.time('for-of loop');
24const squaresForOf: number[] = [];
25for (const num of input) {
26    squaresForOf.push(num * num);
27}
28console.timeEnd('for-of loop');
29
30// --- forEach ---
31console.time('forEach loop');
32const squaresForEach: number[] = [];
33input.forEach((num: number): void => {
34    squaresForEach.push(num * num);
35});
36console.timeEnd('forEach loop');
37
38// --- map ---
39console.time('map');
40const squaresMap: number[] = input.map((value: number): number => value * value);
41console.timeEnd('map');

ประสิทธิภาพจะแตกต่างกันไปขึ้นอยู่กับสภาพแวดล้อมการทำงาน ตัวอย่างเช่น เมื่อลูปทำงานนับล้านครั้ง ความแตกต่างจะชัดเจนมากขึ้น เลือกวิธีการวนลูปที่เหมาะสมที่สุดโดยคำนึงถึงการบำรุงรักษาและประสิทธิภาพ

ใช้วิธีการวนลูปแบบเนทีฟ

 1const squares = [1, 2, 3].map(value => value * value);
 2console.log(squares);
 3
 4const numbers = [1, 2, 3, 4, 5, 6];
 5const evenNumbers = numbers.filter(value => value % 2 === 0);
 6console.log(evenNumbers); // [2, 4, 6]
 7
 8const squaredEvens = numbers
 9    .filter(value => value % 2 === 0) // Keep only even numbers
10    .map(value => value * value);     // Square the remaining values
11
12console.log(squaredEvens); // [4, 16, 36]

เมธอดอย่างเช่น map และ filter อาจทำให้โค้ดอ่านง่ายขึ้นในบางกรณี

เลือกใช้ for...of เพื่อความอ่านง่าย

ควรให้ความสำคัญกับประสิทธิภาพเฉพาะในบางกรณีเท่านั้น เนื่องจากโดยทั่วไปแล้วการเขียนโค้ดที่อ่านง่ายมักมีความสำคัญมากกว่า ตัวอย่างเช่น การให้ความสำคัญกับ for...of สามารถช่วยปรับปรุงความง่ายในการอ่าน

1const fruits = ["apple", "banana", "cherry"];
2
3for (let i = 0; i < fruits.length; i++) {
4    console.log(`${i}: ${fruits[i]}`);
5}
แนวทางปฏิบัติที่ดีที่สุด
1const fruits = ["apple", "banana", "cherry"];
2
3for (const [index, fruit] of fruits.entries()) {
4    console.log(`${index}: ${fruit}`);
5}

ด้วยการให้ความสำคัญกับลูป for...of คุณสามารถเขียนโค้ดที่อ่านง่ายและมีข้อผิดพลาดน้อยลง ดังที่แสดงในตัวอย่างนี้ หากคุณต้องการใช้อินเด็กซ์ของอาร์เรย์ด้วย การใช้ร่วมกันระหว่าง entries() กับ for...of จะมีประสิทธิภาพ

หลีกเลี่ยงข้อผิดพลาดทั่วไป

การแก้ไขคอลเล็กชันระหว่างการวนลูป

1const array = [1, 2, 3];
2for (const value of [...array]) {
3    if (value === 2) {
4        array.push(4); // Avoid this!
5    }
6}
7console.log(array);

การแก้ไขอาร์เรย์ระหว่างการวนลูปอาจส่งผลให้เกิดพฤติกรรมที่ไม่คาดคิด: ใช้สำเนาหากจำเป็น

พิจารณาขอบเขตกรณีต่าง ๆ

1const array: number[] = [];
2for (const value of array) {
3    console.log(value); // No output, but no errors
4}

โค้ดนี้ทำงานได้ดี แต่ถ้าคุณต้องการจัดการกับอาร์เรย์ที่ว่างเปล่า คุณสามารถปรับปรุงได้ดังนี้

1const array: number[] = [];
2if (array.length === 0) {
3    console.log("The array is empty.");
4} else {
5    for (const value of array) {
6        console.log(value);
7    }
8}

การพิจารณากรณีเฉพาะสามารถช่วยป้องกันข้อผิดพลาดในโค้ดถัดไปได้

สรุป

เพื่อเชี่ยวชาญคำสั่ง for ใน TypeScript สิ่งสำคัญคือต้องเข้าใจโครงสร้างลูปต่างๆ ปฏิบัติตามแนวทางปฏิบัติที่ปลอดภัยต่อประเภท และปรับปรุงประสิทธิภาพให้เหมาะสม แนวทางปฏิบัติที่ดีที่สุดเหล่านี้ช่วยให้คุณเขียนโค้ดที่สะอาดขึ้น เชื่อถือได้มากขึ้น และดูแลรักษาได้ง่ายขึ้น

คุณสามารถติดตามบทความข้างต้นโดยใช้ Visual Studio Code บนช่อง YouTube ของเรา กรุณาตรวจสอบช่อง YouTube ด้วย

YouTube Video