乾淨的程式碼是每個成功的軟體專案的基石。作為開發人員,編寫乾淨、可維護的程式碼的能力對於應用程式的效率和壽命至關重要。在本文中,我們將深入研究 JavaScript 中好的和壞的編碼實踐的十個範例,強調編寫乾淨程式碼並提供可操作的見解以幫助您提高開發技能的重要性。

例子

  • 描述性變數名稱:
// Good:

const totalPrice = calculateTotalPrice(quantity, unitPrice);
// Bad:

const t = calcPrice(q, uP);

在一個很好的例子中,變數名稱具有描述性並清楚地表達了它們的目的,從而增強了程式碼的可讀性。相反,糟糕的範例使用神秘的縮寫,使其他人難以理解程式碼的意圖。

  • 一致的格式:
// Good:

function greet(name) {
    return `Hello, ${name}!`;
}
// Bad:

function greet(name){
return `Hello, ${name}!`
}

一致的格式提高了程式碼的可讀性和可維護性。在一個很好的例子中,採用了適當的縮排和間距,並增強了程式碼結構。相反,壞例子缺乏一致性,使得程式碼更難遵循。

  • 避免魔法數字:
// Good:

const TAX_RATE = 0.1;
const totalPrice = subtotal + (subtotal * TAX_RATE);
// Bad:

const totalPrice = subtotal + (subtotal * 0.1);

幻數掩蓋了值的含義,並使程式碼更難維護。在很好的例子中,常數用於表示幻數,提高了程式碼的清晰度和可維護性。

  • 單一責任原則:
// Good:

function calculateTotalPrice(quantity, unitPrice) {
    return quantity * unitPrice;
}

function formatPrice(price) {
    return `$${price.toFixed(2)}`;
}

// Bad:

function calculateAndFormatTotalPrice(quantity, unitPrice) {
    const totalPrice = quantity * unitPrice;
    return `$${totalPrice.toFixed(2)}`;
}

函數應該有單一的責任來提高程式碼的可重複使用性和可維護性。在這個很好的例子中,每個函數都執行特定的任務,並遵循單一職責原則。相反,壞例子將多個職責組合到一個函數中,違反了這個原則。

  • 錯誤處理:
// Good:

function fetchData(url) {
    return fetch(url)
        .then(response => {
            if (!response.ok) {
                throw new Error('Network response was not ok');
            }
            return response.json();
        })
        .catch(error => {
            console.error('Error fetching data:', error);
            throw error;
        });
}
// Bad:

function fetchData(url) {
    return fetch(url)
        .then(response => response.json())
        .catch(error => console.error(error));
}

正確的錯誤處理可以提高程式碼的穩健性,並有助於更有效地辨識和解決問題。在好的範例中,錯誤得到了妥善處理,為開發人員提供了有意義的回饋。相反,壞範例缺乏全面的錯誤處理,可能導致靜默故障。

  • 評論和文件:
// Good:

// Calculate the total price based on quantity and unit price
function calculateTotalPrice(quantity, unitPrice) {
    return quantity * unitPrice;
}
// Bad:

function calculateTotalPrice(quantity, unitPrice) {
    // calculate total price
    return quantity * unitPrice;
}

註釋和文件增強了程式碼的可理解性並促進了開發人員之間的協作。在一個很好的範例中,清晰的註解描述了函數的用途,有助於程式碼理解。相反,壞例子提供的模糊評論幾乎沒有什麼價值。

  • 適當的模組化:
// Good:

export function add(a, b) {
    return a + b;
}

export function subtract(a, b) {
    return a - b;
}
// Bad:

function add(a, b) {
    return a + b;
}

function subtract(a, b) {
    return a - b;
}

模組化程式碼透過將功能組織成內聚的單元來提高可重複使用性和可維護性。在好的例子中,函數被正確地封裝和匯出,促進程式碼重用。相反,壞例子缺乏模組化,使其更難以管理和擴展。

  • DRY 原則(不要重複):
// Good:

const greeting = 'Hello';

function greet(name) {
    return `${greeting}, ${name}!`;
}
// Bad:

function greet(name) {
    const greeting = 'Hello';
    return `${greeting}, ${name}!`;
}

重複的程式碼會增加錯誤的風險並使維護變得困難。一個很好的例子是,將重複的字串提取為常數,遵循DRY原則並提高程式碼的可維護性。相反,壞範例在函數內冗餘地定義了問候語。

  • 有意義的函數名稱:
// Good:

function calculateArea(radius) {
    return Math.PI * radius ** 2;
}
// Bad:

function calc(r) {
    return Math.PI * r ** 2;
}

函數名稱應準確反映其用途,以增強程式碼可讀性。在這個很好的例子中,函數名稱“calculateArea”清楚地表明了它的功能。相反,糟糕的例子使用了神秘的縮寫(“calc”),讓人不清楚函數的作用。

  • 可測試性:
// Good:

function sum(a, b) {
    return a + b;
}

module.exports = sum;
// Bad:

function sum(a, b) {
    console.log(a + b);
}

編寫可測試的程式碼有利於自動化測試,確保程式碼的可靠性和穩定性。在很好的範例中,函數被匯出用於測試目的,從而可以輕鬆設定和執行測試。相反,壞範例包含副作用(console.log),使得測試函數的行為變得具有挑戰性。

  • 正確使用資料結構:
// Good:

const studentGrades = [90, 85, 95, 88];
const averageGrade = studentGrades.reduce((total, grade) => total + grade, 0) / studentGrades.length;
// Bad:

const grade1 = 90;
const grade2 = 85;
const grade3 = 95;
const grade4 = 88;
const averageGrade = (grade1 + grade2 + grade3 + grade4) / 4;

使用適當的資料結構可以增強程式碼的可讀性和可維護性。在很好的例子中,陣列用於儲存學生成績,以便於操作和計算。相反,壞範例依賴單一變數,導致重複且容易出錯的程式碼。

  • 處理非同步操作:
// Good:

async function fetchData(url) {
    try {
        const response = await fetch(url);
        if (!response.ok) {
            throw new Error('Network response was not ok');
        }
        return await response.json();
    } catch (error) {
        console.error('Error fetching data:', error);
        throw error;
    }
}
// Bad:

function fetchData(url) {
    return fetch(url)
        .then(response => {
            if (!response.ok) {
                throw new Error('Network response was not ok');
            }
            return response.json();
        })
        .catch(error => {
            console.error('Error fetching data:', error);
            throw error;
        });
}

正確處理非同步操作可確保程式碼的可靠性和健全性。在一個很好的例子中,async/await 語法用於簡化非同步程式碼並優雅地處理錯誤。相反,壞範例使用嵌套的 Promise,導致回調地獄並降低程式碼可讀性。

  • 依賴管理:
// Good:

import { format } from 'date-fns';
// Bad:

const dateFns = require('date-fns');

有效的依賴管理可以促進程式碼模組化和可擴展性。在一個很好的範例中,ES6 導入語法用於僅從“date-fns”庫導入所需的功能,從而減少不必要的導入並提高效能。相反,糟糕的範例使用 CommonJS require 語法,該語法導入整個“date-fns”模組,可能會使應用程式套件膨脹。

  • 效能優化:
// Good:

const sortedNumbers = [5, 2, 8, 1, 9];
sortedNumbers.sort((a, b) => a - b);
// Bad:

const unsortedNumbers = [5, 2, 8, 1, 9];
const sortedNumbers = unsortedNumbers.sort();

優化程式碼效能可確保高效執行並增強使用者體驗。在一個很好的範例中,使用自訂比較函數呼叫 sort() 方法來按升序對數字進行排序,與預設排序演算法相比,可以獲得更好的效能。相反,壞範例依賴於預設排序演算法,這對於數值陣列可能不是最有效的。

  • Node.js API 中的正確錯誤處理:
// Good:

app.get('/user/:id', async (req, res) => {
    try {
        const user = await getUserById(req.params.id);
        if (!user) {
            return res.status(404).json({ error: 'User not found' });
        }
        res.json(user);
    } catch (error) {
        console.error('Error fetching user:', error);
        res.status(500).json({ error: 'Internal server error' });
    }
});
// Bad:

app.get('/user/:id', async (req, res) => {
    const user = await getUserById(req.params.id);
    if (!user) {
        res.status(404).json({ error: 'User not found' });
    }
    res.json(user);
});

在 Node.js API 中,正確的錯誤處理對於確保穩健性和可靠性至關重要。在好的範例中,錯誤被捕獲並記錄,並且適當的 HTTP 狀態程式碼被返回到客戶端。相反,壞範例無法處理錯誤,可能導致未處理的承諾拒絕和不一致的錯誤回應。

  • 高效率的檔案系統操作:
// Good:

const fs = require('fs').promises;

async function readFile(filePath) {
    try {
        const data = await fs.readFile(filePath, 'utf-8');
        console.log(data);
    } catch (error) {
        console.error('Error reading file:', error);
    }
}
// Bad:

const fs = require('fs');

function readFile(filePath) {
    fs.readFile(filePath, 'utf-8', (error, data) => {
        if (error) {
            console.error('Error reading file:', error);
            return;
        }
        console.log(data);
    });
}

在檔案系統操作中使用 Promise 可以增強程式碼可讀性並簡化錯誤處理。在一個很好的範例中,fs.promises.readFile() 用於非同步讀取文件,並使用 try-catch 處理錯誤。相反,壞範例使用基於回調的方法,這可能導致回調地獄和可讀性較差的程式碼。

  • 高效率的記憶體管理:
// Good:

const stream = fs.createReadStream('bigfile.txt');
stream.pipe(response);

// 壞的:

fs.readFile('bigfile.txt', (error, data) => {
    if (error) {
        console.error('Error reading file:', error);
        return;
    }
    response.write(data);
});

在 Node.js 中使用流進行大檔案處理可以節省記憶體並提高效能。在一個很好的例子中,fs.createReadStream() 和stream.pipe() 用於有效地將資料從檔案串流傳輸到HTTP 回應。相反,壞示例在將整個文件寫入響應之前將其讀入內存,這可能會導致大文件出現內存問題。

  • 正確的模組導出和導入:
// Good:

module.exports = {
    add: (a, b) => a + b,
    subtract: (a, b) => a - b
};

// Bad:

exports.add = (a, b) => a + b;
exports.subtract = (a, b) => a - b;

一致的模組導出和導入實踐提高了程式碼的可讀性和可維護性。在好的例子中, module.exports 用來匯出包含函數的物件,而在壞的例子中,直接使用exports。儘管這兩種方法都有效,但堅持一種約定可以增強程式碼的一致性。

  • 非同步控制流程:
// Good:

async function processItems(items) {
    for (const item of items) {
        await processItem(item);
    }
}
// Bad:

function processItems(items) {
    items.forEach(item => {
        processItem(item);
    });
}

適當的非同步控制流程可確保操作依需求順序或併發執行。在一個很好的範例中,非同步函數與 for...of 迴圈一起使用來順序處理專案,等待每個操作。相反,壞的例子使用了 forEach,它不能很好地處理非同步操作,並且可能會導致意外的行為。


原文出處:https://dev.to/mahabubr/mastering-clean-code-essential-practices-for-developers-1287


共有 0 則留言