แนวปฏิบัติที่ดีที่สุดสำหรับการใช้ลูป 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 ด้วย