Clean Code Applied to JavaScript — Part III. Functions

30 阅读4分钟

本文来自《Clean Code Applied to JavaScript — Part III. Functions》,讨论了编写整洁代码的基本技巧和建议,尤其是关注可复用的代码单元——函数。虽然示例代码使用的是 JavaScript,但这些最佳实践适用于任何编程语言,包括接近硬件层面的语言。

引言

许多人认为整洁代码的原则仅适用于某些编程语言,尤其是那些高级语言。然而,无论使用哪种语言,这些实践都是值得推荐的。只有通过实际行动,我们才能改变现状。以下是一些具体的实践建议,帮助我们在开发中编写更加整洁和高效的代码。

使用默认参数替代短路操作或条件赋值

大多数编程语言都支持为函数参数设置默认值。这使得我们可以避免使用短路操作和条件赋值。

// 使用短路操作
function setName(name) {
    const newName = name || 'Juan Palomo';
}

// 使用默认参数
function setName(name = 'Juan Palomo') {
    // ...
}

减少函数参数(理想情况下不多于 2 个)

减少函数参数的个数可以显著提高代码质量。理想情况下,函数参数不应超过 2 个。如果参数过多,可以将它们组合成一个对象。

// 参数较多的函数
function newBurger(name, price, ingredients, vegan) {
    // ...
}

// 将参数组合成一个对象
function newBurger(burger) {
    // ...
}

// 使用对象解构
function newBurger({ name, price, ingredients, vegan }) {
    // ...
}
const burger = {
    name: 'Chicken',
    price: 1.25,
    ingredients: ['chicken'],
    vegan: false,
};
newBurger(burger);

避免副作用 - 全局变量

副作用会增加代码的复杂性和出错的可能性。应该避免在函数中修改全局变量,尽量将变量作为参数传递。

// 有副作用的函数
let fruits = 'Banana Apple';

function splitFruits() {
    fruits = fruits.split(' ');
}
splitFruits();
console.log(fruits); // ['Banana', 'Apple']

// 无副作用的函数
function splitFruits(fruits) {
    return fruits.split(' ');
}
const fruits = 'Banana Apple';
const newFruits = splitFruits(fruits);
console.log(fruits); // 'Banana Apple'
console.log(newFruits); // ['Banana', 'Apple']

避免副作用 - 可变对象

直接修改对象会导致不可预见的问题。应尽量避免使用可变对象,尤其是在使用 JavaScript 的数组方法时。

// 修改数组本身
const addItemToCart = (cart, item) => {
    cart.push({ item, date: Date.now() });
};

// 返回新的数组
const addItemToCart = (cart, item) => {
    return [...cart, { item, date: Date.now() }];
};

函数应该只做一件事

每个函数只应专注于执行一个任务。对于较大的功能,可以将其拆分为多个小的功能模块。

// 做多件事的函数
function emailCustomers(customers) {
    customers.forEach((customer) => {
        const customerRecord = database.find(customer);
        if (customerRecord.isActive()) {
            email(client);
        }
    });
}

// 拆分后的函数
function emailActiveCustomers(customers) {
    customers
        .filter(isActiveCustomer)
        .forEach(email);
}

function isActiveCustomer(customer) {
    const customerRecord = database.find(customer);
    return customerRecord.isActive();
}

函数应只有一个抽象级别

一个函数应只包含一个抽象级别的代码。如果有不同的抽象级别,应该将其拆分成多个函数。

// 包含多个抽象级别的函数
function parseBetterJSAlternative(code) {
    const REGEXES = [
        // ...
    ];
    const statements = code.split(' ');
    const tokens = [];
    REGEXES.forEach((REGEX) => {
        statements.forEach((statement) => {
            tokens.push( /* ... */ );
        });
    });
    const ast = [];
    tokens.forEach((token) => {
        // lex...
    });
    ast.forEach((node) => {
        // parse...
    });
}

// 拆分后的函数
const REGEXES = [ // ...];
function tokenize(code) {    
    const statements = code.split(' ');
    const tokens = [];
    REGEXES.forEach((REGEX) => {
        statements.forEach((statement) => {
            tokens.push( /* ... */ );
        });
    });
    return tokens;
}
function lexer(tokens) {
    const ast = [];
    tokens.forEach((token) => ast.push( /* */ ));
    return ast;
}
function parseBetterJSAlternative(code) {
    const tokens = tokenize(code);
    const ast = lexer(tokens);
    ast.forEach((node) => // parse...);
}

优先考虑函数式编程而不是命令式编程

函数式编程更容易推理、测试和调试。虽然初学者可能难以适应这种范式,但它在代码可读性和并行编程方面有很大优势。

// 命令式编程
let total = 0;
for (let i = 0; i < items.length; i++) {
  total += items[i].price;
}

// 函数式编程
const total = items
  .map(({ price }) => price)
  .reduce((total, price) => total + price);

函数链式调用

链式调用可以提高代码的可读性和灵活性。通过这种方式,可以将多个简单函数组合在一起,形成复杂的操作。

// 传统方法
class Car {
    constructor({ make, model, color } = car) {}
    setMake(make) {
        this.make = make;
    }
    setModel(model) {
        this.model = model;
    }
    setColor(color) {
        this.color = color;
    }
    save() {
        console.log(this.make, this.model, this.color);
    }
}
const car = new Car('WV','Jetta','gray');
car.setColor('red');
car.save();

// 链式调用
class Car {
    constructor({ make, model, color } = car){}
    setMake(make) {
        this.make = make;
        return this;
    }
    setModel(model) {
        this.model = model;
        return this;
    }
    setColor(color) {
        this.color = color;
        return this;
    }
    save() {
        console.log(this.make, this.model, this.color);
        return this;
    }
}
const car = new Car('WV','Jetta','gray')
.setColor('red')
.save();

结论

在这篇文章中,我们探讨了如何在各种编程语言中应用整洁代码的实践。整洁的函数设计可以显著提高代码的可维护性和可读性。尽管这些建议不是万能的,但它们提供了一套有效的技术,可以帮助我们应对广泛的编程挑战。总结如下:

  1. 使用默认参数而不是短路操作或条件赋值
  2. 减少函数参数(最好不多于 2 个)
  3. 避免副作用 - 全局变量
  4. 避免副作用 - 可变对象
  5. 函数应该只做一件事
  6. 函数应只有一个抽象级别
  7. 优先考虑函数式编程而不是命令式编程
  8. 函数链式调用

这些实践有助于我们编写更加清晰、简洁和高效的代码。 翻 译 —— SQ有空就喝水