如何让你的代码更优雅

76 阅读4分钟

常量赋值

引用数据类型

包括接口中返回的数据,要做好兜底

let lastName = fullName[1] || ''
let propertyValue=Object.attr || 0

指明类型

要按强类型风格写代码定义变量的时候要指明类型,并且在变量声明之后,不要随意的去更改变量的数据类型

// 假设声明三个变量a,b,c
let a,b,c; // difference,定义变量时没有指明类型
let a = "", b = [], c = {}; // good

逻辑判断

==逻辑判断注意

== 表示只要值相等即为真,=== 要求不仅值相等,而且也要求类型相同 使用== 有时候会达不到预期的结果,埋下隐患

0  == ''          // true
0  == '0'         // true
'' == 0           // true
'' == '0'         // false
false == '0'        // true
false == 'false'    // false
false == undefined  // false
false == null       // false
null == undefined   // true
true == 1           // true

数据类型不确定

如果变量的数据类型不确定,那咱就手动的转换一下,让它确定

let total = "6";
if(parseInt(total) === 6){} // grace 手动转换一下数据类型

数组

数组拷贝

let items=['1','2','3'];
const itemCopy = [...items]
// joining arrays 
const odd = [1, 3, 5 ]; 
const nums = [2 ,4 , 6, ...odd]; 

变量赋值

const Arr = [1, 2, 3, 4];
const [first, second] = Arr; 

函数的命名

返回布尔值函数应以is/can/has等单词开头,能够让人更直观的了解到这个函数的功能;获取接口中的数据使用get开头进行命名,动作函数要以动词开头。

// grace
let isSupport = () => {};
let canUpdate = () => {};
let geUserInfo = (user) => {}
let setUserInfo = (user) => {}

优先使用箭头函数

// grace 是不是看着更简介优雅了
let findAge = (arr, age)=> arr.filter(num => num === age)

函数的入参

函数的入参,是能够让使用者,在调用这个函数的时候,能够更加的清晰明了的把这个函数所需要的参数传递给函数,不容易出现,参数传递错误(参数的顺序颠倒等)一些低级,而又不好查找的问题

// difference
// true和false啥意思,没有个注释的话,看上去就是一脸懵逼
function getImages(api, true, false); 
// grace
// 一目了然,知道这些true和false是啥意思
function getImages({
    imageApi: api,
    includePageBackground: true, 
    compress: false,
})

接收参数

如果函数的的参数是对象,也要优先使用解构赋值,上代码

// 假设现在的场景是获取用户的信息上的现用名,和曾用名
// difference
function getFullName(user) {
  const firstName = user.firstName;
  const lastName = user.lastName;
}

// commonly
function getFullName(obj) {
  const { firstName, lastName } = obj;
}

// grace
function getFullName({ firstName, lastName }) {
}

// grace 给它个默认值
function getFullName({firstName, lastName = '无'}) {
}
 
// 觉得参数的名称太长,咱再来个重命名  解构时重命名简化命名
// grace
function getFullName ({firstName: first, lastName: last}) {
 
}

参数效验

更少的嵌套,不满足条件尽早 return,尽可能的减少嵌套,嵌套的层级越少,函数看着越简洁优雅

function test(name, sex = 1) {
  // 不满足条件尽早抛出错误
  if (!name){ 
      throw new Error('没有传递name参数');
  }
}

函数的出参

对象作为返回值,更便于以后添加返回值,以及更改返回值的顺序,相对于数组更加的灵活,更便于扩展

// 函数返回多个值,推荐使用对象作为函数的返回值
// commonly
function processInput(input) {
  return [left, right, top, bottom];
}

// grace
function processInput(input) {
  return { left, right, top, bottom };
}
const { left, right } = processInput(input);

立即执行函数

立即执行函数也推荐写成箭头函数的形式。首先是因为更简洁,并且也绑定好 this(箭头函数不会去改变this的指向)。

(() => {
  console.log('立即执行函数');
})();

优先使用函数式编程

// difference
for(i = 1; i <= 10; i++) {
   a[i] = a[i] +1;
}
// grace
let b = a.map(item => ++item) //是不是更简洁了

函数中过多的采用if else

// commonly
if (a === 1) {
    //...
} else if (a ===2) {
   // ...
} else if (a === 3) {
    //...
} else {
   //...
}
    
// 一般
switch(a) {
    case 1:
        //....
    case 2:
        //....
    case 3:
        //....
    default:
    //....
}

// grace ===》》》 Object
const fruit = {
    1: ['1', '11'],
    2: ['2', '22'],
    3: ['3', '33']
 };
let test = (a) => {
  return fruit[a] || [];
}

// grace ===》》》 Map
const fruit = newMap()
  .set('张三', ['张三丰', '张三力'])
  .set('李四', ['李思维', '李素丽'])
let test = (a) => {
   return fruit.get(a) || [];
}

// grace ===》》》filter
const fruits = [
    { name: '张三', work: 'js' }, 
    { name: '李四', work: 'php' }, 
    { name: '王五', work: 'java' }, 
];
let test = (a) => {
  return fruits.filter(item => item.name === a);
}

// grace===》》》策略模式
let handler = {
    1: () => {
        //....
    },
    2: () => {
        //....
    },
    3: () => {
        //....
    },
    default: () => {
        //....
    }
}
handler[a]() || handler['default']()

温馨小提示

一个函数完成一个独立的功能,不要一个函数混杂多个功能,在项目开发中有一条非常重要的原则【单一原则】所谓的单一原则就是,一个函数(文件),只做一件事情,在开发当中,没有那个项目是开发完成之后,就结束了。需要不断的更新,维护,那么单一原则,就是为了方便开发,和维护的,不要让一个函数“又当爹,又当妈”,这样代码的耦合性太高了,不好维护

其他

判断数组长度

// difference
if (arr.length !== 0) {
    //...
}

// grace
if (arr.length) {
    //...
}


// difference
if (arr.length === 0) {
    //...
}

// grace
if (!arr.length) {
    //...
}

逻辑运算符

if (a === 1) {
    b()
}
//可以写成
a === 1 && b()

const arr = [1,2,3];
if(!arr.length){
   b()
 }
//可以写出
arr.length || b()

// &&判断依赖的键是否存在,防止报错'xxx of undfined'
let user = {
    name: 'Symbol卢',
    age: 18,
    children: {
        name: '小Symbol卢'
    }
}
let childrenName = user.children && user.childre.name

三目运算符

// difference
const a = '';
let b;
if( a === '' ){
    b = 'no'
} else {
    b = 'ok'
}

const a = ''
let b = a ? 'no' : 'ok'; // 'ok'

函数定义

/**
 * @description: 数据类型的检测的第二种方式
 * @param {any} data 要检测数据类型的变量
 * @return {string} type 返回具体的类型名称【小写】
 */
export const isTypeOf = (data) => {
    return Object.prototype.toString.call(data).replace(/[object (\w+)]/, '$1').toLowerCase()
}

使用 Array.includes 来处理多重 || 条件

// difference
if (a === 1 || a === 2 || a === 3 || a === 4) {
    //...
}
// grace
let arr = [1, 2, 3, 4]
if (arr.includes(a)) {
    //...
}

使用 Array.every 和 Array.some 来处理全部/部分满足条件

// grace
const users = [
    { name: '张三', sex:1 },
    { name: '李四', sex:2 },
    { name: '王五', sex:1 }
  ];
function test() {
  // 条件:(简短形式)所有的用户都必须是女
  const isAllGirl = users.every(item => item.sex === 1);
  // 条件:至少一个用户是男的
  const isAnyMan = users.some(item => item.sex === 2);
}

使用正则表达式

const imgType ='jpg'
if(imgType === 'jpg' || imgType === 'png' || imgType === 'gif'){
    console.log('is image')
}
// 使用match匹配正则表达式
if(imgType.match(/.*?(gif|png|jpg)/gi)){
    console.log('is image')
}

连接字符串

let name = 'Symbol'
let message = 'Hello,I'm' + name + 'take care '// 采用传统加号,看着很冗余,且容易出错
// 艾玛,模板字符香,真想
let message = `Hello,I'm ${name} take care `