JS/TS 代码整洁之道的实践指南

338 阅读5分钟

我发现前端同学中,对软件工程领域的巨著《代码整洁之道》讨论的甚少,团队中甚至还有一些多年的前端根本不知道这本书。 可能本身前端的东西太多了,已经学不过来了,再加上JS本身的灵活性,导致大家对代码整洁似乎没那么看重。看重的人,也往往缺乏实践或者不知道如何去实践。 本文总结了一些自己的经验,也总结了一些博客,汇总一篇JS/TS 代码指南。如有兴趣,还可以参考我的另一篇博文:SOLID原则与实践 - 掘金 (juejin.cn)

变量名

  1. 团队内部可以自己定义,合适的变量名应该能让人看出来这是什么东西,便于理解和维护. 例子:

        currentDate 好过 time
        tmp  好过  s/a/b这种无意义的命名
        常量使用全大写 
    
  2. 保持命名的一致性 例如,用户相关的,大家都用user开头,比如userInfo,userName等

  3. 不要使用魔法数字 使用常量代替魔法数字

  4. 不用过多的使用上下文 比如

    class User{
      name:string
     }
    

    好过

    class User{
    userName:string
    }
    
  5. 减少无用变量
    比如

     return createUser();
     const user  = createUer();
     return user;
    

函数

  1. 合适的函数名 和变量名一样,函数名需要能够直观的解释这个函数的作用。比如:getCurrentDay 我们还可以使用固定的前缀,比如:
    1. 发送服务请求相关的可以用requestXXX命名 ,
    2. 像服务器提交数据可以用submitXXX命名,
    3. 无参数但是有返回值的函数可以用getXXX命名,
    4. 创建了一个新对象的函数可以用createXX命名,
    5. 有参数但是无返回值的函数可以用handlerXXX命名,
    6. 有参数且有返回值的函数可以用processXXX命名,
    7. 返回值是布尔值的函数可以用isXXX/hasXXX命名,
    8. 如果对入参的对象有更改,可以使用 updateXXX,deleteXXX等命名。
  2. 合适参数默认值
function createUser(name = "nobody") {
 // ...
}

3.参数不要太多,否则可以考虑拆分函数,或者封装参数。 比如

function createUser(name = "nobody",age='18',sex='man',licenceId='') {
// ...
}

可以封装为

function createUser({name = "nobody",age='18',sex='man',licenceId=''}) {
 // ...
}
createUser({
   name = "congbai"age='28',
   sex='man',
   licenceId=''
})

或者将其拆分为

 const user  = createUserByName('congbai')
 user.setAge(20)
 user.setSex('man')
  1. 单一职责 老生长谈了,可参考SOLID原则与实践 - 掘金 (juejin.cn) 该处的难点在于,如何定义‘职责’。比如我们可以把'创建用户'作为一个职责,也可以将其细分为'创建用户名,设置用户年龄,设置用户性别'三个职责。这个要根据自己的业务场景去区分。 6个参考标准:

  2. 如果一个职责里面的代码超过50行,那肯定能再拆出来一些职责。

  3. 如果一段逻辑被两次以上重用,可以拆出来公用

  4. 如果一段逻辑没有副作用,可以拆出来

  5. if 的判断条件如果过多,可以拆分出来

  6. if/else内部的逻辑,尽量拆分出来

  7. 数组里面的map,reduce,foreach传入的代码片段,可以拆分出来

  8. 多层嵌套一定拆出来,最多两层

  9. 传入的参数如果在函数内被直接当做if的条件使用,那么这个if相关的逻辑应该在该函数之外处理: 例如:

     function createUser(sex='man'){
         if(sex==='man')
         {
             return createMan()
         }
         else{
             return createWoman()
         }
     }
    
    functin getUser(){
     const sex= getSex();
     return createUser(sex);
    }
    
    

    可以修改为

    functin getUser(){
     const sex= getSex();
     if(sex ==='man'){
        return createMan()
     }esle{
      return createWoman()
     }
    }
     
    
  10. 善用es6的解构语法进行复制和赋值
    比如

     user={
     ...anotherUser,
     age:28
     }
     
     allUser=[...oldUser,...newUser]
    
  11. 减少函数的副作用

    1. 避免修改参数以外的任何变量
    2. 如有可能,尽量返回一个新的对象,而不是对参数中的对象进行修改。 比如
    function addUserToList(user,list){
       user.age=19;
       list.push(user);
    }
    可以替换成
    function addUserToList(user,list){
       
       return [...list,{...user,age:19}]
    }
    

    之所以说有可能,是因为这种方式会带来性能的损耗,因此要衡量使用。

  12. 尽量使用函数式编程 比如数组中的foreach,filter等等。

  13. 使用多态和设计模式来减少if/else的判断,降低耦合性。 还是参见SOLID原则与实践 - 掘金 (juejin.cn)

  14. 使用Promise代替回调函数

类设计

  1. 尽量使用get set访问器对属性进行修改

  2. 多用组合,少用继承

  3. 如非必要,不要修改原型

  4. set访问器可以返回'this',以便进行链式调用 比如

    class User {

     setName(name){
       this.name = name;
       return this;
     }
     setAge(age){
       this.age = age
       return this;
     }
    

    } user.setName('葱小白').setAge(28)

  5. 类中方法的顺序最好按一定的顺序排列。比如在A中调用了B,那么B应该位于A之后,便于阅读。

其他

  1. 这些原则是参考的依据,不是需要严格遵守的。

  2. 没有一次性就能写的漂亮的代码,需要定期的按照这些原则进行修正

  3. 缩进,命名,短代码是代码像诗一样漂亮的保证

  4. 合理的命名能有效降低注释的必要性,但是该注释的地方还是要注释。当code review时,别人看不懂的地方,都应该有注释。