12、组织数据(上):拆分变量、字段改名、以查询取代派生变量

数据是代码的血液。我见过太多系统,逻辑写得还行,但数据组织一塌糊涂,最后改个需求要翻遍整个项目。说白了,数据组织不好,代码再“整洁”也是空中楼阁。

这一章我们聚焦三个最基础、也最常用的重构手法:拆分变量字段改名以查询取代派生变量。它们看起来简单,但用好了,能让你的代码清晰度提升一个档次。

1. 拆分变量:一个变量只做一件事

你见过那种一个变量被反复赋值、每次含义都不同的代码吗?

let temp = 2 * (height + width);
console.log(temp);
temp = height * width;
console.log(temp);

这个 temp 变量,第一轮是周长,第二轮是面积。我刚开始写代码时也这么干,觉得省变量名很“聪明”。直到有一次我 debug 到凌晨三点,才发现自己把周长当面积传给了下游函数……

正确的做法是:一个变量只承载一个含义

const perimeter = 2 * (height + width);
console.log(perimeter);
const area = height * width;
console.log(area);

你看,现在每个变量职责清晰,不会混淆。而且 const 一用,连意外修改的可能性都堵死了。

核心原则:如果变量被多次赋值,且每次赋值的含义不同,就应该拆分成多个变量。

2. 字段改名:名字就是最好的注释

我接手过一个老项目,有个字段叫 a,我以为是“年龄(age)”,结果发现是“地址(address)”。这种命名,简直是给后人挖坑。

字段改名看似简单,但有个坑:改名字不只是改一处。你得确保所有引用点都同步更新。好在现代 IDE 都支持重命名重构,但如果你用的是纯文本编辑器,那就得小心了。

举个例子,一个订单类里有个字段叫 n

class Order {
  constructor(n) {
    this.n = n;
  }
}

这个 n 是啥?数量?编号?名字?没人知道。我建议改成有业务含义的名字:

class Order {
  constructor(customerName) {
    this.customerName = customerName;
  }
}
我的习惯:字段命名遵循“业务术语优先”原则。如果业务方叫“客户名称”,代码里就别叫“name”或“custName”,直接叫“customerName”。这样产品经理看代码都能看懂。

改名字时,记得用“迁移式改名法”:先新增字段,逐步替换引用,最后删除旧字段。别一次性改完,尤其是大项目,容易出事。

3. 以查询取代派生变量:能算出来的就别存

这是我最喜欢的一个重构手法。很多新手喜欢把能推导出来的数据也存成字段,结果导致数据不一致。

比如,一个订单类里同时存了 items(商品列表)和 totalPrice(总价):

class Order {
  constructor(items) {
    this.items = items;
    this.totalPrice = this.calculateTotal();
  }

  calculateTotal() {
    return this.items.reduce((sum, item) => sum + item.price, 0);
  }
}

问题来了:如果有人直接修改了 items 数组,但忘了更新 totalPrice,数据就错了。我曾在项目中遇到过这种 bug,排查了两天才发现是某个同事在业务代码里直接 push 了商品,没调计算总价的方法。

解决方案很简单:把派生数据变成查询方法

class Order {
  constructor(items) {
    this.items = items;
  }

  get totalPrice() {
    return this.items.reduce((sum, item) => sum + item.price, 0);
  }
}

现在 totalPrice 是个 getter,每次访问都实时计算。数据永远一致,而且你少维护一个字段。

注意:如果计算开销很大(比如遍历百万级数据),或者调用频率极高,那还是得考虑缓存。但大多数业务场景下,实时计算完全够用。

知识体系图

下面这张图总结了本章三个重构手法的核心逻辑和适用场景:

组织数据(上):三个核心手法 拆分变量 一个变量只做一件事 • 变量被多次赋值 • 每次含义不同 • 拆成多个 const • 消除歧义 • 提升可读性 例:temp → perimeter, area 字段改名 名字就是最好的注释 • 使用业务术语 • 避免缩写 • 迁移式改名 • 同步更新所有引用 • 利用 IDE 重构 例:n → customerName 以查询取代派生变量 能算出来的就别存 • 派生数据用 getter • 避免数据不一致 • 减少字段维护 • 实时计算 • 注意性能开销 例:totalPrice → getter 目标:数据清晰、一致、易维护

避坑指南

  • 拆分变量时别过度:如果一个变量只在循环里用,且每次赋值含义相同(比如累加器),那就不需要拆。
  • 字段改名要同步文档:我曾经改了一个字段名,但忘了更新接口文档,结果前端同事对接时一脸懵。改完名记得通知相关方。
  • 派生变量不是都不能存:如果计算开销极大(比如全表扫描),或者需要历史快照,那还是得存。但这种情况很少见。
一个小技巧:当你犹豫一个字段该不该存时,问自己一个问题:“如果这个字段的值和它依赖的数据不一致了,我能接受吗?” 如果不能,就别存,用查询代替。

好了,这一章就到这里。数据组织是代码整洁的基石,这三个手法虽然基础,但用好了能解决很多实际问题。下一章我们继续聊组织数据的其他手法,到时候见。


公众号:蓝海资料掘金营,微信deep3321