变量
- 使用有意义、可读性好的变量
- 使用 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 获取历史版本。
- 避免位置标记
- 避免在源文件中写入法律评论
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。