TypeScript 中 for 迴圈的最佳實踐
本文將解釋在 TypeScript 中使用 for 迴圈的最佳實踐。
YouTube Video
TypeScript 中 for 迴圈的最佳實踐
for 語句是一種用於執行重複操作的基礎且強大的語法。在 TypeScript 中,利用類型安全性並以可讀性和可維護性為目標編寫代碼,可以讓您撰寫更高效且錯誤較少的代碼。
選擇正確的迴圈類型
TypeScript 提供了幾種不同的迴圈結構,適用於不同的使用案例。選擇適合的迴圈對於程式碼的清晰度和性能至關重要。
標準 for 迴圈
1for (let i = 0; i < 10; i++) {
2 console.log(i);
3}當您需要精確控制迴圈索引時,標準的 for 迴圈是理想的選擇。
最佳實踐
1const maxIterations = 10;
2for (let i = 0; i < maxIterations; i++) {
3 console.log(i);
4}在撰寫 for 語句時,記住以下要點可以幫助您撰寫出更安全且易於閱讀的代碼。
- 使用
let作為索引變數- 使用
let替代var能將範圍限於區塊內,防止意外行為的發生。
- 使用
- 使用常量和具描述性的變數名稱,使循環邊界更明確
- 避免使用魔術數字並使用有意義的變數名稱可以提高可讀性。
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}此外,通過在 tsconfig.json 中啟用 noImplicitAny,可以防止未顯式設定類型的變量被隱式分配為 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}考慮邊緣情況可以幫助防止後續程式碼中的錯誤。
結論
要掌握 TypeScript 中的 for 語句,了解各種迴圈結構、遵循型別安全的實踐以及優化效能至關重要。這些最佳實踐有助於您編寫更乾淨、更可靠且更易於維護的程式碼。
您可以在我們的 YouTube 頻道上使用 Visual Studio Code 來跟隨上述文章一起學習。 請也查看我們的 YouTube 頻道。