使用链式调用优化代码:一个实际案例

在软件开发中,代码的可读性和可维护性是至关重要的。一种常见的优化技巧是使用链式调用来简化复杂的操作,提高代码的清晰度和简洁性。在本文中,我将通过一个实际案例来演示如何使用链式调用来优化代码。

一个例子

我们先通过一个示例直观地感受一下不同的编程方式是如何处理同一个业务逻辑需求的,以便于更深入地了解链式调用带来的便利。

假设后端在响应中返回了一个包含了多个对象的数组类型的数据,它的结构如下,classes属性中记录了每个人最近一周每天上的课程,记录中的每一项既可能是字符串,也可能是字符串组成的数组(代表所上课程不止一种):

ini 复制代码
const data = [
  { name: 'Alice', classes: ['Math', 'English', ['Physics', 'Chemistry'],'English'] },
  { name: 'Bob', classes: ['Math', ['Biology', 'Chemistry']] }
];

现在为了分析学生们的课程安排,我们需要把在classes属性中出现过的所有课程都记录下来,并按照字母顺序对其排序,相同的课程只需要出现一次即可。下面就来看看不同的开发者可能会如何实现这样的功能。

初级开发者的代码

ini 复制代码
function getAllCourses(data) {
  let resultMap = {};

  //遍历每一条记录的classes字段,然后使用对象实现去重功能
  for (let i = 0; i < data.length; i++) {
    for (let j = 0; j < data[i].classes.length; j++) {
      let classes = data[i].classes[j];
      if (typeof classes === "string" && !resultMap[classes]) {
        //处理字符串类型的情况
        resultMap[classes] = 1;
      } else if (Array.isArray(classes)) {
        //处理数组类型的情况
        classes.forEach((item) => {
          if (!resultMap[item]) {
            resultMap[item] = 1;
          }
        });
      }
    }
  }
  //从对象中生成并返回最终结果
  return Object.keys(resultMap).sort((a, b) => a.localeCompare(b));
}

const data = [
  { name: "Alice", classes: ["Math", "English", ["Physics", "Chemistry"]] },
  { name: "Bob", classes: ["Math", ["Biology", "Chemistry"]] },
];

const result = getAllCourses(data);
console.log(result); // [ 'Biology', 'Chemistry', 'English', 'Math', 'Physics' ]

上述代码虽然实现了所要求的功能,但但暴露了太多实现细节。有如下几个问题:

  1. 代码结构较为复杂,嵌套了两层循环,可读性稍显不足,理解起来有一定难度。
  2. 如果输入的数据格式不符合预期,可能会导致意外错误,缺乏代码的健壮性。
  3. 代码使用了命令式的编程风格,缺乏灵活性和可扩展性。
  4. 当需要添加新功能或修改现有功能时,由于代码结构复杂,可能需要对代码进行大量的修改。

中级开发者的代码

javascript 复制代码
function getAllCourses(data) {
  return sortAndUnique(
    flatmap(
      data.map((item) => item.classes),
      []
    )
  );
}

//排序去重
function sortAndUnique(arr) {
  let resultMap = {};
  arr.forEach((i) => (resultMap[i] = 1));
  return Object.keys(resultMap).sort((a, b) => a.localeCompare(b));
}

//数组扁平化
function flatmap(arr, result) {
  if (Array.isArray(arr)) {
    arr.map((item) => {
      flatmap(item, result);
    });
  } else {
    result.push(arr);
  }
  return result;
}
const data = [
  { name: "Alice", classes: ["Math", "English", ["Physics", "Chemistry"]] },
  { name: "Bob", classes: ["Math", ["Biology", "Chemistry"]] },
];

const result = getAllCourses(data);
console.log(result); // [ 'Biology', 'Chemistry', 'English', 'Math', 'Physics' ]

上述代码质量明显比前面的要好。这份代码遵循了"单一职责"的开发原则,将数组的类型判断、数组的扁平化、数组的排序和去重等可重用的方法从业务逻辑中剥离出来,形成了独立的方法。

高级开发者的代码

ini 复制代码
const getAllCourses = (data) => {
  let result = data;
  function map(fn) {
    result = result.map(fn);
    return api;
  }
  function flattenDeep() {
    function flatten(arr) {
      return arr.reduce(
        (acc, val) =>
          Array.isArray(val) ? acc.concat(flatten(val)) : acc.concat(val),
        []
      );
    }
    result = flatten(result);
    return api;
  }
  function sortBy() {
    result = result.sort();
    return api;
  }
  function sortedUniq() {
    result = Array.from(new Set(result));
    return api;
  }
  function value() {
    return result;
  }
  const api = {
    map,
    flattenDeep,
    sortBy,
    sortedUniq,
    value,
  };
  return api;
};
// 使用示例
const data = [
  { name: "Alice", classes: ["Math", "English", ["Physics", "Chemistry"]] },
  { name: "Bob", classes: ["Math", ["Biology", "Chemistry"]] },
];

const result = getAllCourses(data)
  .map((item) => item.classes)
  .flattenDeep()
  .sortBy()
  .sortedUniq()
  .value();
console.log(result); // [ 'Biology', 'Chemistry', 'English', 'Math', 'Physics' ]

上述代码

  1. 代码结构清晰,每个功能分离明确。每个方法只关注自己的功能,这使代码容易理解和维护。
  2. 链式调用风格使得代码简洁,调用者可以直观地看到数据是如何一步步处理的。
  3. 如果需要添加更多的处理步骤,只需在 api 对象中添加新的方法即可,方便扩展。

总结

封装链式调用的关键是确保每个方法都返回正确的对象,以支持后续的链式调用,并且要确保链式调用的方法在设计时考虑周全,易于理解和使用。

相关推荐
小羊没烦恼!13 小时前
T-SQL查询进阶--理解SQL SERVER中的分区表
服务器·开发语言·前端·javascript·html
Highcharts.js13 小时前
AI图表开发工具Highcharts Assist|自然语言生成图表代码
javascript·人工智能·highcharts·开发神器
志尊宝14 小时前
Vue3 零基础每日笔记(087):Vue3 高频面试题(下)
前端·javascript·vue.js·笔记·ecmascript·#vue.js
const_qiu16 小时前
第二章 2.6:初始化 NestJS 服务端 —— TypeScript 后端框架体验
前端·javascript·typescript
miofly16 小时前
GitHub 今日推荐|sweety-handdraw-video:文章转手绘口播视频
javascript·开源·github
用户831348593069817 小时前
Vue3 事件:常用用法与开发高频坑点
前端·javascript·vue.js
漫步人生走在路上17 小时前
用小语种SEO突破外贸B2B天花板:法语、德语市场的实测数据
开发语言·前端·javascript·人工智能·搜索引擎·ecmascript
ydjs678899-bot19 小时前
您的Next.js中间件匹配器配置可能会跳过您认为它保护的路由
开发语言·javascript·中间件
Chengbei1119 小时前
JsOwl|AI 赋能 JS 敏感信息扫描器,AST + 正则、source‑map 源码还原、登录态爬虫输出交互式 HTML 报告
开发语言·javascript·网络·人工智能·爬虫·网络安全·自动化
ShineWinsu20 小时前
对于JavaScript:初识JavaScript以及输入输出
java·开发语言·前端·javascript·css·面试·html