编写可维护的 JavaScript
这是出版于2013年的书。编写可维护的JavaScript的重要性不言而喻,特别对于团队工作来讲。统一规范的编码规范、严谨的编码风格,能在代码的维护时节约大量的人力成本。
基本的格式化
- 缩进层级:缩进层级到底采用制表符(tab)/2个空格/4个空格,都不重要,重要的是在一个团队中约定一种缩进风格。无关优劣,在这里风格统一最重要。另一个重要的点就是,切忌制表符和空格混用。
语句结尾:是否要分号结尾。虽然JS分析器有自动分号插入机制(ASI),但添加分号依然是广为推崇的编码风格。
function foo() { return { name: 'laoli' } } /*上面的代码在ASI插入分号后:*/ function foo() { return; { name: 'laoli' }; } /* 显然不是我们的预期 */
行的长度:为保证在编程和阅读时不那么别扭,尽量保证代码不会导致编辑器窗口横向滚动。一般风格指南中,将一行的长度限制在80个字符,如果超过80个字符,考虑在合适的位置手动换行。
- Java语言规范中源码里单行长度不超过80个字符,文档中代码单行长度不超过70个字符
- Android开发者编码风格指南规定单行代码长度不超过100个字符
- 非官方的Ruby编程规范规定单行代码长度不超过80个字符
- Python编程规范中规定单行代码长度不超过79个字符
换行:主要涉及到超过上一条的一行的长度时如何缩进。在运算符后换行,下一行添加两个层级的缩进,比如规范中一个缩进是4个空格,那这里就要在下一行添加8个空格。
/* 普通超出 */ someHandler(arguments1, arguments2, arguments3, arguments4, arguments5, arguments6); /* if条件超出 */ if(condition1 && condition2 && condition3 && condition4 && condition5 && condition6){ doSomething(); } /* 赋值语句超出,保持和 = 右边对齐 */ var result = something1 + something2 + something3 + something4 + something5 + something6;
空行:适当的添加空行,会大大增加代码的可读性。
- 方法之间
- 方法中的局部变量和第一条语句之间
- 在多行或者单行注释之前
- 方法内的逻辑片段之间
命名:甭管大驼峰小驼峰还是匈牙利命名法。统一规范和风格最重要,在保证其他人可以通过名字很容易看得懂命名的含义的前提下,在细分场景中:
- 变量和函数:小驼峰命名的前提下,变量保证以名词作为前缀,函数保证以动词作为前缀
- 常量:大写字母加下滑线。虽然ES6之前并没有常量的概念,但实际开发过程中,我们依然会常常用到常量。比如规定的最大数量可以使用
MAX_COUNT
- 构造函数:大驼峰命名。构造函数是被当做JS中的类来理解的
直接量
- 字符串:无特殊命名,但有一点,换行字符串采用换行符
\
拼接是不符合JavaScript语法的 - 数字:采用十进制,不省略小数点前后的0
对象直接量:创建对象更合适的办法是使用对象直接量,缩进及换行规则推荐如下
var book = { title: 'abc', author: 'def' };
- 字符串:无特殊命名,但有一点,换行字符串采用换行符
注释
单行注释:
//单行注释
- 注释单独占一行时,和上一行之间留一个空行
- 注释单独占一行时,注释的缩进和紧接着的语句的缩进保持一致
- 注释和代码在一行时,至少保证和代码之间有一个缩进,如果代码+注释超过了80个字符,注释尽量单独占一行
//
尽量不要用在多行注释中
多行注释:
/* 多行注释 */
多行注释每一行最左侧添加一个
*
/* * 第一段注释 * 又一段注释 */
- 代码尾部注释不要采用多行注释
- 何时使用注释
- 难于理解的代码
- 可能会被误认为错误的代码
- 浏览器特性的hack
- 文档注释
- 某些自动化工具会根据注释自动生成文档
- 所有的方法:对方法期望的参数和可能的返回值添加注释描述
- 所有的构造函数:对自定义类型和期望的参数添加注释描述
语句和表达式
所有的块语句都应当使用花括号,包括:
- if
- for
- while
- do...while...
- try...catch
花括号的对齐方式
/* 方式1 */ if (condition) { dosomething(); } else { doSomethingElse(); } /* 方式2 */ if(condition) { doSomething(); } else { doSomethingElse(); }
语法层面,这两对齐方式都是对的,也各有自己的习惯人群。但主流的JavaScript风格指南都推荐方式1,方式2可能会导致ASI分号插入错误导致代码不按预期执行。
块语句间隔
块语句主要有三种间隔风格,看习惯。大多数风格指南推荐风格2
/* 风格1 */ if(condition){ doSomething() } /* 风格2 */ if (condition) { doSomething() } /* 风格3 */ if ( condition ) { doSomething() }
switch语句:执行完一个“case”后连续执行下一个“case”,被成为
fall through
,不写break即可,在某些场景下,这样操作会带来出其不意的效果,比如著名的达夫设备
,但为了代码的可读性考虑,不建议使用fall through
,确需使用时,必须添加对应的注释。for-in循环:
for-in
循环一般用于对象的属性,包括实例自己的属性和从原型链继承而来的属性。在很多规范中有提到,在使用for-in
循环时,需要先通过hasOwnPrototype
判断是否是实例本身的属性,如果不这么做,JSHint
和JSLint
都会提示错误。如果需要遍历包含从原型链继承而来的属性时,可以不使用hasOwnPrototype
但必须添加注释说明。同时,for-in
被很多的编程风格指南禁止用于数组对象,这一点也需要注意。