js代码整洁之道(重构)

最近在重构项目代码,结合《重构》和《代码整洁之道》以及Airbnb JavaScript总结一下,重构一下我们的代码,让我们的代码更加整洁,精简。话不多说,燥起来吧!!

1. 尽量使用const定义变量,避免使用var

这可以确保你不能重新赋值变量,也可以避免导致错误和让人难以理解的代码

// bad
var a = 1;
var b = 2;

// good
const a = 1;
const b = 2;
2. 如果要重新赋值定义变量,尽量使用let

let和const块级作用域,ver函数作用域,可以避免重复定义造成的错误

// bad
var count = 1;
if (true) {
  count += 1;
}

// good
let count = 1;
if (true) {
  count += 1;
}
3. object如果使用动态属性,尽量使用计算属性

一个地方可以定义所有的属性

function getKey(k) {
  return `a key named ${k}`;
}

// bad
const obj = {
  id: 5,
  name: 'San Francisco',
};
obj[getKey('enabled')] = true;

// good
const obj = {
  id: 5,
  name: 'San Francisco',
  [getKey('enabled')]: true,
};
4. 使用object属性简写
const lukeSkywalker = 'Luke Skywalker';

// bad
const obj = {
  lukeSkywalker: lukeSkywalker,
};

// good
const obj = {
  lukeSkywalker,
};
5. 取值时使用解构
const userInfo = {
  age:18,
  name: '小明',
  address: '广东深圳' 
}
// bad
this.userName = userInfo.name;
this.useAge = userInfo.age;
this.useAddress = userInfo.address;

// good
const { age, name, address } = userInfo
this.userName = name;
this.useAge = age;
this.useAddress = address;

// Array
const list = [ '小明', '小红', '小花' ]
// bad
const xiaohong = list[1]; // 小红

// good
const [ , xh, ,] = list
const xiaohong = xh; // 小红
6. 使用语义化命名变量
// bad
const yyyymmdstr = moment().format("YYYY/MM/DD");

// good
const currentDate = moment().format("YYYY/MM/DD"); 


// bad
getUserInfo();
getClientData();
getCustomerRecord();

//good
getUser();
7. 使用常量命名

方便搜索和解释来源

// bad
// 86400000 怎么来的?
setTimeout(blastOff, 86400000);

// good
const MILLISECONDS_IN_A_DAY = 60 * 60 * 24 * 1000; //86400000;

setTimeout(blastOff, MILLISECONDS_IN_A_DAY);
8. 避免使用精神映射
// bad
const locations = ["Austin", "New York", "San Francisco"];
locations.forEach(l => {
  doSomeThings(l); // l 是干什么的
});

//good
const locations = ["Austin", "New York", "San Francisco"];
locations.forEach(location => {
  doSomeThings(location);
});
9. 使用默认参数代替条件
// bad
function createUser(name) {
  const userName = name || "小明";
  // ...
}

// good
function createUser(name = "小明") {
  // ...
}
10. 避免过多的函数参数
// bad
function createMenu(title, body, buttonText, cancellable) {
  // ...
}
createMenu("Foo", "Bar", "Baz", true);

// good
function createMenu({ title, body, buttonText, cancellable }) {
  // ...
}

createMenu({
  title: "Foo",
  body: "Bar",
  buttonText: "Baz",
  cancellable: true
})
11. 函数应该只做一件事情
// bad
function emailClients(clients) {
  clients.forEach(client => {
    const clientRecord = database.lookup(client);
    if (clientRecord.isActive()) {
      email(client);
    }
  });
}

// good
function emailActiveClients(clients) {
  clients.filter(isActiveClient).forEach(email);
}

function isActiveClient(client) {
  const clientRecord = database.lookup(client);
  return clientRecord.isActive();
}
12. 不要使用全局函数

可以避免使用相同的操作是发生冲突

// bad 
Array.prototype.diff = function diff(comparisonArray) {
  const hash = new Set(comparisonArray);
  return this.filter(elem => !hash.has(elem));
};

// good
class SuperArray extends Array {
  diff(comparisonArray) {
    const hash = new Set(comparisonArray);
    return this.filter(elem => !hash.has(elem));
  }
}
13. 使用函数式编程代替命令式编程
// bad
const orderList = [
  {
    name: "可乐",
    price: 5
  },
  {
    name: "雪碧",
    price: 10
  }
];
let totalPrice = 0;
for(let i = 0; i < orderList.length;i++) {
  totalPrice += orderList[i].price
}

// good
const orderList = [
  {
    name: "可乐",
    price: 5
  },
  {
    name: "雪碧",
    price: 10
  }
];

const totalPrice = orderList.reduce(
(total, item) => (total + item.price),0);
14. 把条件语句封装成函数
// bad
if (order.state === 'already' && isEmpty(orderList)){ }

// good
function getOrderInfo (){
  return order.state === 'already' && isEmpty(orderList)
}
if(getOrderInfo()){ }

15. 以卫语句取代嵌套条件表达式
// bad
function getOrderPrice() {
  let result;
  if (price) {
    result = getPrice();
  } else {
    if(adPrice){
      result = getAdPrice();
    }else{
      if(stockPrice) {
        result = getStockPrice();
      }else {
        result = getOtherPrice();
      }
    }
  }
  return result;
}

// good
function getOrderPrice() {
  if (price) return getPrice();
  if (adPrice) return getAdPrice();
  if (stockPrice) getStockPrice();
  return getOtherPrice();
}
16. 以管道取代循环
// bad
const names = [];
for (const i of listMans) {
  if (i.obj === 'staff') {
    names.push(i.nam);
  }
}

// good
const names = listMans
.filter(list=>list.obj === 'staff')
.map(item=>item.name)
17. 多个返回值时尽量使用对象解构
// bad
function processInput(input) {
  return [left, right, top, bottom];
}

// 调用的时候要考虑先后顺序
const [left, __, top] = processInput(input);

// good
function processInput(input) {
  return { left, right, top, bottom };
}

// 不用考虑顺序
const { left, top } = processInput(input);
18. 返回string类型的时候使用字符串模板
// bad
function sayHi(name) {
  return 'How are you, ' + name + '?';
}

// good
function sayHi(name) {
  return `How are you, ${name}?`;
}
19. 不要导出可变的绑定
// bad
let foo = 3;
export { foo };

// good
const foo = 3;
export { foo };
20. 如果导出单个模块,尽量使用默认导出
// bad
export function foo() {}

// good
export default function foo() {}
21. 获取属性的使用 [ ]
const luke = {
  jedi: true,
  age: 28,
};

function getProp(prop) {
  return luke[prop];
}

const isJedi = getProp('jedi');
22. 多个或者条件,使用Array.includes(option)
// bad
function isShowMenu() {
  const routerName = this.$route.name;
  const list = ['collect', 'admin', 'order', 'other']; 
  return routerName === 'collect' || routerName === 'admin'
   || routerName === 'order' || routerName === 'other'
}

// good
function isShowMenu() {
  const routerName = this.$route.name;
  const list = ['collect', 'admin', 'order', 'other'];
  return list.includes(routerName);
}
23. 避免使用不必要的三元表达式
// bad
const foo = a ? a : b;
const bar = c ? true : false;
const baz = c ? false : true;

// good
const foo = a || b;
const bar = !!c;
const baz = !c;
24. 提前让函数退出代替嵌套条件分支

if如果有执行ruturn,else就可以不要了

// bad
function foo() {
  if (x) {
    return x;
  } else {
    return y;
  }
}

// bad
function cats() {
  if (x) {
    return x;
  } else if (y) {
    return y;
  }
}

// bad
function dogs() {
  if (x) {
    return x;
  } else {
    if (y) {
      return y;
    }
  }
}

// good
function foo() {
  if (x) {
    return x;
  }

  return y;
}

// good
function cats() {
  if (x) {
    return x;
  }

  if (y) {
    return y;
  }
}

// good
function dogs(x) {
  if (x) {
    if (z) {
      return y;
    }
  } else {
    return z;
  }
}
25. 如果变量过长,尽量使用换行
// bad
if (foo === 123
  && bar === 'abc') {
  doThing();
}
// good
if (foo === 123 && bar === 'abc') {
  doThing();
}

// bad
if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
  doThing();
}
// good
if (
  (foo === 123 || bar === 'abc')
  && doesItLookGoodWhenItBecomesThatLong()
  && isThisReallyHappening()
) {
  doThing();
}
26. 导出的文件名尽量和路劲文件名一致
// bad
import CheckBox from './checkBox'; 
import FortyTwo from './FortyTwo'; 
import InsideDirectory from './InsideDirectory'; 

// good
import CheckBox from './CheckBox'; 
import fortyTwo from './fortyTwo'; 
import insideDirectory from './insideDirectory'; 
27. 首字母缩写和首字母缩写应该总是全部大写,或者全部小写
// bad
import SmsContainer from './containers/SmsContainer';
// good
import SMSContainer from './containers/SMSContainer';
// best
import TextMessageContainer from './containers/TextMessageContainer';
28. 判断是否有属性是boolean,尽量使用isVal()或者hasVal
// bad
if (!dragon.age()) {
  return false;
}

// good
if (!dragon.hasAge()) {
  return false;
}
29. 合理使用循环
// bad
// 判断是什么浏览器
function getBrowser(){
    const str = navigator.userAgent;
    if (str.includes('QQBrowser')) {
 return 'qq';
    } else if (str.includes('Chrome')) {
 return 'chrome';
    } else if (str.includes('Safari')) {
        return 'safri';
    } else if (str.includes('Firefox')) {
        return 'firefox';
    } else if(explorer.indexOf('Opera') >= 0){
        return 'opera';
    } else if (str.includes('msie')) {
        return 'ie';
    } else {
        return 'other';
    }
};

// good
// 循环判断,将对应关系抽象为配置,更加清晰明确
function getBrowser(){
    const str = navigator.userAgent;
    const list = [
        {key: 'QQBrowser', browser: 'qq'},
        {key: 'Chrome', browser: 'chrome'},
        {key: 'Safari', browser: 'safari'},
        {key: 'Firefox', browser: 'firefox'},
        {key: 'Opera', browser: 'opera'},
        {key: 'msie', browser: 'ie'},
    ];
    for (let i = 0; i < list.length; i++) {
        const item = list[i];
        if (str.includes(item.key)) {return item.browser};
    }
    return 'other';
}
posted @ 2021-04-12 09:16  童心虫鸣  阅读(351)  评论(0编辑  收藏  举报