Clean code JavaScript(2)

本文摘自 GitHub 上一个优秀的仓库,这个仓库主要列出了一些代码的优化技巧,阅读后有一定启发,因此将一些对自己日后编码会有受益的技巧记录下来。

明确函数的功能

函数的功能应当遵循单一原则,即一个函数只做一件事情、只有一种功能。例如以下代码:

function sendEmail() {
    employees.forEach(employee => {
    const address = address.findBy(employee);
    if(isAddressUnderChina(address)) {
        email(employee);
    }
  });
}

上述代码的逻辑为:给地址在中国的员工发送邮件。其实 sendEmail 函数做了两件事情:一件是找出在中国的员工,第二件是发送邮件。根据函数功能单一的原则,可以将上面的代码的功能进行拆分:

function sendEmail() {
     employees.filter(isEmployeeInChina).forEach(employee => email(employee));
}
function isEmployeeInChina(employee) {
    return  isAddressUnderChina(employee);
}

这样进行拆分后,逻辑更加清晰,同时函数的功能也变的更加利于测试。

函数功能如其名

如同上述,函数功能单一的原则下,函数名显得极为重要。我们可以从一个意义明确的函数名判断函数的功能,这样的函数名,提升了代码的可读性。例如:

function addToDate(date, month) {
  // ...
}
const date = new Date();
addToDate(date, 1);

如同上述的代码,仅仅看 addToDate 这个函数名,并不能快速的知道这个函数是给日期添加了什么,只能去阅读函数具体的实现,才知道是要给当前日期添加一个月。那么这个变量名就是极为不好的,可以命名的再具体一些:

function addMonthToDate(date, month) {
  // ...
}
const date = new Date();
addMonthToDate(date, 1);

这样重命名之后,函数功能如其名,代码可读性进一步提高。

抽取公共的代码

我们通常会碰到这种情况,两个函数的大部分功能是相似的,仅仅有一部分功能不同。那么针对这种情况,可以提取出两个函数的公共部分:

function showDeveloperList(developers) {
  developers.forEach(developer => {
    const expectedSalary = developer.calculateExpectedSalary();
    const experience = developer.getExperience();
    const githubLink = developer.getGithubLink();
    const data = {
      expectedSalary,
      experience,
      githubLink
    };
    render(data);
  });
}
function showManagerList(managers) {
  managers.forEach(manager => {
    const expectedSalary = manager.calculateExpectedSalary();
    const experience = manager.getExperience();
    const portfolio = manager.getMBAProjects();
    const data = {
      expectedSalary,
      experience,
      portfolio
    };
    render(data);
  });
}

上述的代码中,有一些逻辑是重复的,比如“获取研发和管理者的期望薪水和工作经验”部分。我们可以将其抽取出来,优化如下:

function showEmployeeList(employees) {
  employees.forEach(employee => {
    const expectedSalary = employee.calculateExpectedSalary();
    const experience = employee.getExperience();
    const data = {
      expectedSalary,
      experience
    };
    switch (employee.type) {
      case "manager":
        data.portfolio = employee.getMBAProjects();
        break;
      case "developer":
        data.githubLink = employee.getGithubLink();
        break;
    }
    render(data);
  });
}

这样优化之后,函数变为了一个,代码量减少了很多,而且逻辑更加的清晰,减轻了阅读者的负担。但是代码的抽象要根据实际情况进行,要进行合理的抽象,而不要过度抽象,过度的抽象反而起到了副作用,一切优化都要以利于可读性为准。

使用 Object.assign 进行默认赋值

相信以下的代码我们都遇见过:

function async getOrderBy(id) {
  const order = await api.getOrderBy(id);
  this.order.id = order.id || 0;
  this.order.type = order.type || 'sale';
  this.order.name = order.name || '';
  this.order.status = order.status !== undefined ? order.status : 'pocessing';
}

以上代码没有问题,将接口的数据赋值给 this.order,同时没有值的情况下,给予默认值。但是很显然语句很罗嗦,我们可以利用 Object.assign API 简化以上写法:

function async getOrderBy(id) {
  const defaultOrder = {
    id: 0,
    type: 'sale',
    name: '',
    status: 'processing',
  };
  const order = await api.getOrderBy(id);
  this.order = Object.assign(defaultOrder, order);
}

利用 Object.assign 的特性,将两个对象进行合并,如果两个有重复的属性时,第二个的属性值将会替换第一个的属性值,具体用法可以看这里。如果你接触过 Vue.js 框架,那么你应该知道 Vue 官方也推荐这种方式去更新数据,因为 Object.assign 总是会返回一个新的对象。

不要将函数的参数作为标志/状态

有些时候我们为了省事,会将函数的参数作为标志/状态来使用,函数内部根据这个标志状态的不同去执行不同的逻辑:

function createFile(name, temp) {
  if (temp) {
    fs.create(`./temp/${name}`);
  } else {
    fs.create(name);
  }
}

这样做固然没错,但是这样违背了函数的功能单一原则,函数内部应该只做一件事情。我们可以将上述代码改写如下:

function createFile(name) {
  fs.create(name);
}
function createTempFile(name) {
  fs.create(`./temp/${name}`);
}

这样函数的逻辑更加清晰,同时函数功能如其名,更加利用我们阅读。

原文地址:Clean code JavaScript (2) · 语雀

https://juejin.im/post/5e1ab210e51d4530e60e3b05

「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论