在框架功能日渐完善的现今,绝大部分需求场景都可以借助框架来完成。 但是作为一个有追求的程序员,绝不应该以此为终点。 除了完成需求,还更应该写出一手风格简洁、易于理解的代码。 毕竟,框架可以帮助你处理 视图与模型 的绑定,但是不会告诉你 如何抽象数据

本文是平时 Code Review 的总结,以此为警示。

变量

常量提取

// bad
if (file.fileSize > 200 * 1024 * 1024) {
  stopUploadingFiles();
}

// good
const MAX_FILE_SIZE = 200 * 1024 * 1024; // 200m

if (file.fileSize > MAX_FILE_SIZE) {
  stopUploadingFiles();
}

解释

如果文件大小限制变为 300m,比起 查找并全局替换,直接修改常量值能更快满足产品需求变动。

多余的临时变量

// bad
function personFactory(config) {
  const person = new Person(config);
  return person;
}

// good
function personFactory(config) {
  return new Person(config);
}

函数

强行副作用

const objArray = [{ checked: false }, { checked: false }];

// bad
const makeAllChecked = (array) => {
  array.forEach((item) => {
    item.checked = true;
  });
  return array;
};

makeAllChecked(objArray);

// good
const getAllChecked = array => (
  array.map(item => Object.assign(item, {
    checked: true,
  }))
);

const checkedObjArray = getAllChecked(objArray);

职责不单一

const ALLOWED_MUSIC_FILE_TYPE_LIST = ['wav', 'aac', 'flac', 'mp3'];

// bad
const isMusicFile = (fileName) => {
  const fileTypeString = fileName.split('.').pop().toLowerCase();
  return (ALLOWED_MUSIC_FILE_TYPE_LIST.indexOf(fileTypeString) > -1);
};

// good
const getFileType = fileName => (fileName.split('.').pop().toLowerCase());
const isMusicFile = fileName => (
  ALLOWED_MUSIC_FILE_TYPE_LIST.indexOf(getFileType(fileName)) > -1
);

callback 判断

// bad
function asyncFunction(timeout, callback) {
  // done
  if (callback !== undefined) {
    callback();
  }
}

// good
function asyncFunction(timeout, callback) {
  // done
  if (callback === 'function') {
    callback();
  }
}

解释

既然 callback 的目的是 函数调用,那就应该直接判断是否为 function,毕竟也可以传入 string 等其他乱七八糟类型的参数。

迂回的返回值

const ALLOWED_MUSIC_FILE_TYPE_LIST = ['wav', 'aac', 'flac', 'mp3'];

// bad
// 判断是否是允许的音乐文件
const isMusicFile = (fileName) => {
  const fileTypeString = fileName.split('.').pop().toLowerCase();
  if (ALLOWED_MUSIC_FILE_TYPE_LIST.indexOf(fileTypeString) > -1) {
    return true;
  }
  return false;
};

// good
// 判断是否是允许的音乐文件
const isMusicFile = (fileName) => {
  const fileTypeString = fileName.split('.').pop().toLowerCase();
  return (ALLOWED_MUSIC_FILE_TYPE_LIST.indexOf(fileTypeString) > -1);
};

Array

用错方法

// https://www.zhihu.com/question/63732073
// 用 JavaScript 编写,实现从键盘输入 n 个整数,求该组整数的平均值,并将大于平均值的整数输出

// bad one
const getTargetNumbers = numbers =>
  numbers.filter(
    number => (number > (
      numbers.reduce((prev, number) => (number + prev), 0) / numbers.length
    ))
  );

console.log(getTargetNumbers([1, 2, 3, 4, 5, 6, 7]))

// bad two
let arr = [1, 2, 3, 4, 5, 6, 7];
let average = arr.reduce((sum, now) => { return sum + now; }, 0) / arr.length;
arr.map(item => {
  if(item > average) {
    console.log(item)
  }
);

// good
const averageNumber = (numbers) => (
  numbers.reduce((prev, number) => (number + prev), 0) / numbers.length
);

const getTargetNumbers = numbers => (
  numbers.filter(
    number => (number > averageNumber(numbers))
  )
);

相关参考:

条件

扭捏的判断

const numberArray = [1, 2, 3, 4];

// bad
if (numberArray.indexOf(1) !== -1) {}

// good
if (numberArray.indexOf(1) > -1) {}

Vue

复杂的 template 内渲染条件

<template>
  <div v-if="(index > 1) && (array.indexOf(item) > -1)">
  </div>
</template>

解释

复杂的 DOM 的渲染条件,应该放在 computed 内或者抽离成为 method

jQuery

扩大选择器范围

// bad
const $error = $('.error');

// good
const $error = $('#error-container .error');

解释

.error 是一个非常常用的类名,如果直接 $('.error') 进行相关操作,无异于 修改全局变量

选择器缓存

// bad
const $error = $('#error-container .error');

// good
const $errorContainer = $('#error-container');
const $error = $errorContainer.find('.error');

其他资料

以上。