代码重构技巧:提取方法、重命名与简化条件

FreeGuideOnline 最新 2026-07-01

代码重构技巧:提取方法、重命名与简化条件

重构是在不改变代码外部行为的前提下,改善其内部结构的过程。它能有效提升代码的可读性、可维护性,降低后续修改引入缺陷的风险。本教程将聚焦三个最基础、最常用的重构技巧,帮助你一步一个脚印地改善既有代码。

提取方法

什么是提取方法?

当你发现一段代码逻辑相对独立,可以实现某个清晰的小功能时,就可以把这段代码拿出来,放进一个独立的方法(或函数)中,并用意图清晰的名字命名它。

何时应该提取方法?

  • 一个方法过长,包含多个不同层次的抽象。
  • 某段代码需要写注释才能让人明白它“做什么”。
  • 几个地方重复出现了相同或极其相似的代码片段。

具体步骤

  1. 识别出可以独立出来的代码块,它最好只有一个明确的职责。
  2. 创建一个新方法,根据它的“意图”而非“做法”命名(例如 calculateTax 而非 multiplyAndAdd)。
  3. 将原位置的代码替换为对新方法的调用。
  4. 检查原作用域内的局部变量,如果仅在新方法内使用,就直接搬过去;如果在原方法后面还有使用,则需要作为参数传入或作为返回值传出。

重构前后示例

假设有一段计算订单总价,并应用折扣的代码:

// 重构前
function printOrderTotal(order) {
  let total = 0;
  for (let i = 0; i < order.items.length; i++) {
    total += order.items[i].price * order.items[i].quantity;
  }
  
  // 应用折扣逻辑
  let discount = 0;
  if (order.customer.isVIP) {
    discount = total * 0.1;
  } else if (total > 1000) {
    discount = total * 0.05;
  }
  
  total = total - discount;
  console.log(`订单总额: ${total}`);
}

观察发现,折扣计算逻辑独立且可以自说明,于是提取出来:

// 重构后
function calculateDiscount(total, customer) {
  if (customer.isVIP) {
    return total * 0.1;
  }
  if (total > 1000) {
    return total * 0.05;
  }
  return 0;
}

function printOrderTotal(order) {
  const total = order.items.reduce(
    (sum, item) => sum + item.price * item.quantity,
    0
  );
  const discount = calculateDiscount(total, order.customer);
  console.log(`订单总额: ${total - discount}`);
}

提取出的 calculateDiscount 不仅让主流程更简洁,还可以被其他地方复用。

重命名

重视名字的力量

代码被阅读的次数远多于被编写的次数。模糊、具有误导性或过时的命名会直接拖慢理解和调试速度。重命名是最经济、最安全的重构之一,几乎所有现代IDE都支持一键安全重命名。

重命名变量

变量名应该回答“它里面放了什么”,避免单字母或无意义缩写(循环中常见的 ij 可酌情使用)。

  • 坏例子:d, tp, arr
  • 好例子:daysSinceLastLogin, totalPrice, activeUsers
// 重构前
let d = 0;
for (let u of users) {
  if (u.a) d++;
}

// 重构后
let activeUserCount = 0;
for (let user of users) {
  if (user.isActive) activeUserCount++;
}

重命名函数/方法

函数名应该描述它“做什么”或“返回什么”,通常以动词开头。

  • 坏例子:data(), handle(), process()
  • 好例子:getUserProfile(), validateEmail(), sendNotification()

重命名类/模块

类名用名词或名词短语,表达其职责。

  • 坏例子:Manager, DataProcessor, Utils
  • 好例子:UserSession, EmailSender, DateFormatter

小提示:如果你需要花很长时间才能为某个元素起出恰当的名字,往往说明它的职责不够单一,可能需要进一步拆分。

简化条件表达式

复杂的 if-else 会快速让代码变得难以理解。下面介绍几种简化条件表达式的实用模式。

分解条件

当一个条件判断本身的逻辑很复杂时,将其提取成一个具有清晰名字的函数。

// 重构前
if (user.age >= 18 && user.country === 'CN' && !user.isBanned && user.points > 100) {
  // ...
}

// 重构后
function isEligibleForPromotion(user) {
  return user.age >= 18 
    && user.country === 'CN' 
    && !user.isBanned 
    && user.points > 100;
}

if (isEligibleForPromotion(user)) {
  // ...
}

合并条件

当几个条件分支返回相同的结果或执行相同的动作时,将它们合并为一个条件表达式。

// 重构前
if (order.status === 'cancelled') return false;
if (order.status === 'refunded') return false;
if (order.amount <= 0) return false;

// 重构后
if (order.status === 'cancelled' || order.status === 'refunded' || order.amount <= 0) {
  return false;
}

使用卫语句(Guard Clauses)

当方法中有多个分支,但只有一个或少数几个正常情况时,可以尽早将异常或边界情况返回,避免深层嵌套。

// 重构前
function getDiscountedPrice(user, product) {
  let price = product.price;
  if (user.isLoggedIn()) {
    if (user.isMember()) {
      if (product.isOnSale()) {
        price = price * 0.5;
      } else {
        price = price * 0.9;
      }
    }
  }
  return price;
}

// 重构后
function getDiscountedPrice(user, product) {
  if (!user.isLoggedIn()) return product.price;
  if (!user.isMember()) return product.price;
  if (product.isOnSale()) return product.price * 0.5;
  return product.price * 0.9;
}

引入断言

当某个条件在本该不可能出现的情况下仍然进行检查时,可以将其替换为断言(或抛出明确的异常),即在代码中声明“此时不应发生某情况”。这不是替代正常的错误处理,而是用于明确编程约定。

// 重构前
if (currentUser == null) {
  throw new Error('currentUser 不应为空');
}
// 后续直接使用 currentUser

// 重构后(使用断言或直接信任调用约定,并加防御性检查)
console.assert(currentUser != null, 'currentUser 不应为空');
// 或者使用专门的断言库

使用断言能让代码意图更清晰,向阅读者传达“这里理论上不可能为null”。

总结

重构不是一次性的浩大工程,而是伴随日常开发的小步改进。掌握提取方法、重命名与简化条件这三个核心技巧,你就能开始对任何混乱的代码进行“微修复”。务必养成习惯:每添加新功能前,先让所在代码区更干净一点;每修复一个Bug后,顺手改善周边的可读性。配合自动化测试,你可以安全、自信地让代码库持续进化。