在有些时候,代码的可读性远比性能更高的代码要有用得多。像是我们的业务代码,他会非常频繁的进行更改,这就要求在阅读代码的时候不要有过多的精力去理解代码是干什么用的,更能减少因为代码理解错误导致修改之后出现BUG的几率。下面是我用到过的,并且觉得很好用的一些方式。
小函数:单一职责
- 将复杂的逻辑分解成更小的、只做一件事情的函数。每个函数应该易于理解、测试和复用。
- 长函数通常难以阅读和维护。如果一个函数超过了“一屏”(这只是一个启发式规则),或者做了多件不同的事情,就应该考虑拆分它。
1function handleUser(user) {2 // 验证用户3 if (!user.name || !user.email) {4 console.log("无效用户");5 return;6 }7
8 // 格式化用户信息9 const info = `用户姓名: ${user.name}, 邮箱: ${user.email}`;10
11 // 打印用户信息12 console.log(info);13}14
151 collapsed line
16handleUser(user);1function isValidUser(user) {2 return user.name && user.email;3}4
5function formatUserInfo(user) {6 return `用户姓名: ${user.name}, 邮箱: ${user.email}`;7}8
9function printUserInfo(user) {10 if (!isValidUser(user)) {11 console.log("无效用户");12 return;13 }14
15 const info = formatUserInfo(user);5 collapsed lines
16 console.log(info);17}18
1920printUserInfo(user);很多人觉得把一个函数拆分之后来回跳转就很烦,这一点需要你自己平衡,合理的拆分函数,这一点非常重要,在我看来把一个函数尽可能地拆分成小函数,然后组合这些小函数远比写一大串的代码要好维护的多,虽然会有多次跳转。
如果你不能一次性的把一个函数全部拆分,其实可以先写完代码,然后去优化这个代码,将一部分确定的只做一件事情的那部分代码抽出来单独写成一个方法,多拆解次之后这个大函数就清晰明了多了。
有时候拆着拆着发现,拆分出来的函数可能只有一行代码,这不是脱裤子放屁吗。其实可以这么去理解,一个函数代表的才是一个操作,如果只是一行代码的话那就只是一行代码,他没有任何意义。
避免深层嵌套
- 卫语句:通过尽早处理边缘情况或无效输入来简化复杂条件逻辑、减少嵌套
- 提前返回: 与卫语句类似,在函数中尽早返回结果或错误。
- 使用 Map, Filter, Reduce: 对于数组操作,使用这些高阶函数通常比手写带有 if 条件的 for 循环更扁平、更具声明性。
- 状态机: 对于具有许多状态和转换的复杂逻辑,状态机模式可以使流程更清晰。
卫语句
1function processOrder(order) {2 if (order) {3 if (order.items && order.items.length > 0) {4 if (!order.isCancelled) {5 console.log("正在处理订单:", order.id);6 }7 }8 }9}1function processOrder(order) {2 if (!order) return;3 if (!order.items || order.items.length === 0) return;4 if (order.isCancelled) return;5
6 console.log("正在处理订单:", order.id);7}提前返回
1function greetUser(user) {2 if (user) {3 if (user.name) {4 console.log(`你好,${user.name}!`);5 } else {6 console.log("你好,陌生人!");7 }8 } else {9 console.log("没有用户信息。");10 }11}1function greetUser(user) {2 if (!user) {3 console.log("没有用户信息。");4 return;5 }6
7 if (!user.name) {8 console.log("你好,陌生人!");9 return;10 }11
12 console.log(`你好,${user.name}!`);13}使用高阶函数
1const users = [2 { name: "小明", age: 17 },3 { name: "小红", age: 20 },4 { name: "大壮", age: 25 }5];1let adultNames = [];2for (let i = 0; i < users.length; i++) {3 if (users[i].age >= 18) {4 adultNames.push(users[i].name);5 }6}7const result = adultNames.join(", ");8console.log(result); // 小红, 大壮1const result = users2 .filter(user => user.age >= 18)3 .map(user => user.name)4 .join(", ");5
6console.log(result); // 小红, 大壮状态机
使用状态机处理订单状态流程,不同状态之间的转换有限制,比如:
1创建 → 已付款 或 已取消2已付款 → 已发货3已发货 → 已送达1// 状态转移表2const orderStateMachine = {3 created: ['paid', 'cancelled'],4 paid: ['shipped'],5 shipped: ['delivered'],6 delivered: [],7 cancelled: []8};9
10// 当前订单状态11let orderState = 'created';12
13// 状态切换函数14function transitionTo(newState) {15 const allowed = orderStateMachine[orderState];13 collapsed lines
16 if (allowed.includes(newState)) {17 console.log(`订单状态:${orderState} → ${newState}`);18 orderState = newState;19 } else {20 console.error(`无法从 "${orderState}" 切换到 "${newState}"`);21 }22}23
24// 测试流程25transitionTo('paid'); // created → paid26transitionTo('delivered'); // 不能直接跳过 shipped27transitionTo('shipped'); // paid → shipped28transitionTo('delivered'); // shipped → delivered注释
- 尽可能的删掉你那傻逼的注释,比如:
1// 验证用户2if (!user.name || !user.email) {3 console.log("无效用户");4 return;5}6
7// 格式化用户信息8const info = `用户姓名: ${user.name}, 邮箱: ${user.email}`;注释的作用在”为什么”方面,才更能体现出它的作用,而不是解释在干什么。
- 尽可能的更新注释
在阅读一段代码的时候发现注释已经跟代码无法正确匹配了,如果你不能及时更新,那就果断一点,直接删了他,有时候注释带来的误解会让你不敢去修改这段代码。