3

变量

  • 使用有意义、可读性好的变量
  • 使用 ES6 的 const 声明常量
  • 对功能类似的变量名采用统一的命名风格
  • 使用易于检索名称

    举例
    // 反例
    for (var i = 0; i < 525600; i++) {
      runCronJob();
    }
    
    // 正例
    var MINUTES_IN_A_YEAR = 525600;
    for (var i = 0; i < MINUTES_IN_A_YEAR; i++) {
      runCronJob();
    }
    
  • 使用说明变量(即有意义的变量名)
  • 显式优于隐式(变量名尽量简洁明了)
  • 避免重复的描述
  • 避免无意义的条件判断

    举例
    var currentPage='';
    var pageNumInfo = JSON.parse(localStorage.getItem('pageNumInfo'));
    if (pageNumInfo) {
        currentPage = parseInt(pageNumInfo[0].pageNum);
    } else {
        currentPage = 1;
    }
    // 以上代码片段可用以下代码取代
    var pageNumInfo = JSON.parse(localStorage.getItem('pageNumInfo')); 
    var currentPage = parseInt(pageNumInfo[0].pageNum) || 1;
    

函数

  • 函数参数

    函数参数理想情况下应该不超过 2 个。当确实需要多个参数时,大多情况下可以考虑将这些参数封装成一个对象。
  • 保证函数功能的单一性

    功能不单一的函数将导致难以重构、测试和理解。功能单一的函数易于重构,并使代码更加干净。
  • 提高函数名的可读性(函数名应明确表明其功能)
  • 函数应该只做一层抽象

    当函数需要的抽象多于一层时通常意味着函数功能过于复杂,需将其进行分解以提高其可重用性和可测试性。
  • 避免在一个函数中写重复的代码
  • 采用默认参数精简代码
  • 使用 Object.assign() 设置默认对象
  • 不要使用标记(Flag)作为函数参数(会破坏函数功能的单一性)
  • 避免副作用

    函数副作用:当函数产生了除了“接受一个值并返回一个结果”之外的行为时,称该函数产生了副作用。比如写文件、修改全局变量等。
    程序在某些情况下确实需要副作用这一行为,如先前例子中的写文件。这时应该将这些功能集中在一起,不要用多个函数/类修改某个文件。用且只用一个 service 完成这一需求。
  • 不要写全局函数
  • 采用函数式编程
  • 封装判断条件
  • 避免“否定条件”的判断
  • 避免条件判断

    许多情况下通过使用多态(polymorphism)可以达到同样的目的。
    // 反例
    class Airplane {
      //...
      getCruisingAltitude() {
        switch (this.type) {
          case '777':
            return getMaxAltitude() - getPassengerCount();
          case 'Air Force One':
            return getMaxAltitude();
          case 'Cessna':
            return getMaxAltitude() - getFuelExpenditure();
        }
      }
    }
    
    // 正例
    class Airplane {
      //...
    }
    
    class Boeing777 extends Airplane {
      //...
      getCruisingAltitude() {
        return getMaxAltitude() - getPassengerCount();
      }
    }
    
    class AirForceOne extends Airplane {
      //...
      getCruisingAltitude() {
        return getMaxAltitude();
      }
    }
    
    class Cessna extends Airplane {
      //...
      getCruisingAltitude() {
        return getMaxAltitude() - getFuelExpenditure();
      }
    }
    
  • 避免类型判断
  • 避免过度优化
  • 无效代码及时删除

对象和数据结构

  • 使用 getters 和 setters

    使用 getters 和 setters 获取对象的数据远比直接使用点操作符具有优势,为什么呢??
    1、当需要对获取的对象属性执行额外操作时。
    2、执行 set 时可以增加规则对要变量的合法性进行判断。
    3、封装了内部逻辑。
    4、在存取时可以方便的增加日志和错误处理。
    5、继承该类时可以重载默认行为。
    6、从服务器获取数据时可以进行懒加载。
  • 让对象拥有私有成员。(可以通过闭包实现)

  • 列表项目
  • 单一职责原则(SRP)
  • 开闭原则(OCP)

    代码实体(类,模块,函数等)应该易于扩展,难于修改。
    即代码模块的功能应该要方便用户拓展而不是修改源码
  • 利斯科夫替代原则(LSP)

    子类对象应该能够替换其超类(父类)对象被使用。
  • 接口隔离原则(ISP)

    客户端不应该依赖它不需要的接口,一个类对另一个类的依赖应该建立在最小的接口上。
  • 依赖反转原则(DIP)

    该原则有两个核心点:
    1、高层模块不应该依赖于低层模块。他们都应该依赖于抽象接口。
    2、抽象接口应该脱离具体实现,具体实现应该依赖于抽象接口。
  • 使用 ES6 的 classes 而不是 ES5 的 Function

    典型的 ES5 的类(function)在继承、构造和方法定义方面可读性较差。
    当需要继承时,优先选用 classes。
    但是,当在需要更大更复杂的对象时,最好优先选择更小的 function 而非 classes。
  • 使用方法链
  • 优先使用组合模式而非继承

测试

  • 单元测试,单一的测试每个概念

并发

  • 用 Promise 替代回调(支持 ES6 的情况,优先使用)
  • async 和 await(支持 ES7 的情况,优先使用)

错误处理

  • try/catch 捕获异常
  • 不要忽略被拒绝的 promises

格式化

  • 大小写一致
  • 调用函数的函数和被调函数应放在较近的位置

    当函数间存在相互调用的情况时,应将两者置于较近的位置。理想情况下,应将调用其他函数的函数写在被调用函数的上方。

注释

  • 只对存在一定业务逻辑复杂性的代码进行注释。注释并不是必须的,好的代码是能够让人一目了然,不用过多无谓的注释。
  • 被注释掉的代码及时删除
  • 不需要版本更新类型注释。需要时可以使用 git log 获取历史版本。
  • 避免位置标记
  • 避免在源文件中写入法律评论

参考


Evelyn
258 声望12 粉丝

一只野生媛媛