Javascript Code Style

前言

个人认为编码规范是很重要的,它可以达到提高代码质量,增强团队的开发协作的目的.

作为强迫症患者,如果看到不符规范的代码,我会十分难受.

以下规范主要根据书籍 Maintainable Javscript 翻译而来, 结合其他资料,根据个人喜好,有改动.

缩进

缩进使用2个或4个空格, 具体选哪个, 与团队约定好即可.

本文的缩进是4个空格的

不要使用tab, 更不要空格与tab混合使用

1
2
3
4
// Good
if (true) {
doSomething();
}

不使用tab的原因是,目前还没有确定的规范说tab代表了几个空格,你当然可以设置,但该设置也许换个编辑器就失效了(我就吃过这种苦头), 更别说换一台电脑打开了.

换行

单行最好不超过80个字符,当然也不用真的去数,当编辑器出现横向的滚动条时,就果然换行吧.

操作符放在行尾,如逗号,加号等.

续行要比正常的代码多一个级别的缩进

1
2
3
4
5
6
7
8
9
10
11
// Good 两次缩进,共8个空格
doSomething(argument1, argument2, argument3, argument4,
argument5);
// Bad 一次缩进,共4个空格
doSomething(argument1, argument2, argument3, argument4,
argument5);
// Bad 逗号没放在第一行的行尾
doSomething(argument1, argument2, argument3, argument4
, argument5);

命名

命名是机算机界两大难题之一

变量

变量应该遵循以下规则:

  • 驼峰命名
  • 名词开头
  • 尽量不要带$, 除非是类似jQuery查询返回的对象
  • 尽量不要用下划线, 除非你在用underscoreloadash
1
2
3
4
5
6
7
8
9
10
11
// Good
var accountNumber = "8401-1";
// Bad: 首字母大写了
var AccountNumber = "8401-1";
// Bad: 动词开头
var getAccountNumber = "8401-1";
// Bad: 使用了下划线
var account_number = "8401-1";

函数的名字以动词开头, 其余规则同变量命名规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Good
function doSomething() {
// code
}
// Bad: 首字母大写了
function DoSomething() {
// code
}
// Bad: 以名词开头
function car() {
// code
}
// Bad: 使用了下划线
function do_something() {
// code
}

常量使用const关键字,字母全部大写,单词之前使用下划线分割

1
2
3
4
5
6
7
8
// Good
var TOTAL_COUNT = 10;
// Bad: 驼峰命名
var totalCount = 10;
// Bad: 大小写混合使用
var total_COUNT = 10;

对象的私有属性/私有方法,以下划线开头

1
2
3
4
5
6
7
8
// Good
var object = {
_count: 10,
_getCount: function () {
return this._count;
}
};

文件

  • 一般文件名 推荐单词全部小写, 多个单词以中划线分割

  • JSX文件名则使用首字母也大写的驼峰命名规则,不使用分割符

  • 文件夹命名规则 推荐同一般文件名

路径(url)

有时需要js来定制路由规则, 则此时就涉及到url的命名

参考
google

https://developer.chrome.com/multidevice/webview/gettingstarted

以及facebook

https://facebook.github.io/react/blog/2016/07/22/create-apps-with-no-configuration.html

我推荐url命名也全部单词小写, 多个单词以中划线分割

操作符

操作符两边要有一个空格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Good
var found = (values[i] === item);
// Good
if (found && (count > 10)) {
doSomething();
}
// Good
for (i = 0; i < count; i++) {
process(i);
}
// Bad: 缺少空格
var found = (values[i]===item);
// Bad: 缺少空格
if (found&&(count>10)) {
doSomething();
}
// Bad: 缺少空格
for (i=0; i<count; i++) {
process(i);
}

判断相等

尽量使用 === and !== 替代 == and != 避免发生类型转换

1
2
3
4
5
// Good
var same = (a === b);
// Bad: 使用 ==
var same = (a == b);

三元表达式

一般而言, 三元素表达式用来简化赋值操作, 而不是为了简化if-else

1
2
3
4
5
6
7
8
// Good
var value = condition ? value1 : value2;
// Bad: 没有赋值操作,应该使用if-else
condition ? doSomething() : doSomethingElse();
// Good: 在return中, 是特殊情况
return (size > 0 ? size : defaultSize);

特殊情况:

JSX中, 为了方便, 我经常会用第二种写法, 我觉得也是可以接受的, 但也仅限于JSX

基本类型

字符串

字符串变量建议使用单引号,考虑到html的元素的属性是双引号的,使用单绰号可以方便写出下面的代码:

1
document.body.innerHTML = '<div class="alert" role="alert">你的浏览器实在<strong>太太太太太太旧了</strong></div>';

字符串最好用一行来表示,不要使用反斜杠在新的一行创建字符串

1
2
3
// Bad: 使用反斜杠形成两行
var longString = 'Here's the story, of a man \
named Brady.';

如果真的要多行, 请使用ES6的模板字符串

模板字符串的另一个好处是, 字符串里可以使用变量, 因此也不再需要使用加号来拼接字符串.

1
2
3
4
// 字符串中嵌入变量
var name = 'Bob', time = 'today';
`Hello ${name}, how are you ${time}?`

数字

整数不要使用八进制(这个应该没人用吧)

1
2
3
4
5
6
7
8
// Good 10进制
var count = 10;
// Good 16进制
var num = 0xA2;
// Good
var num = 1e23;

浮点数至少带有一个小数位(以js的机制而言,js里的数字全是浮点数,这里是指某一变量会存储带小数的数值)

1
2
3
4
5
6
// Good
var price = 10.0;
var price = 10.00;
// Bad: 只有小数点,后面没有数字
var price = 10.;

下面是有争议的例子:

1
2
// Bad or Good ?
var price = .1;

书中认为这种写法并不好.

但这种写法在CSS中是属于精简的/值得鼓励的.

考虑到写js的人也会写CSS, 我认为这种写法是可以接受的, 反正我喜欢这样写😁

null

null值只用在以下四种情况中:

  1. 初始化一个将会存放对象的变量
  2. 检测一个变量是否在初始化时, 以对象赋值
  3. 检测函数的参数是否是对象
  4. 函数返回值期望是对象时
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Good
var person = null;
// Good 函数期望返回的是对象
function getPerson() {
if (condition) {
return new Person("Nicholas");
} else {
return null;
}
}
// Good
var person = getPerson();
if (person !== null){
doSomething();
}
// Bad: 检测一个未初始化的变量
var person;
if (person != null){
doSomething();
}
// Bad: 检测是否有传参 arg4
function doSomething(arg1, arg2, arg3, arg4){
if (arg4 != null){
doSomethingElse();
}
//注: 本例中,对于检测是否有传参, if(arg4) 即可
}

undefined

不要直接使用undefined

若要查看变量是否已定义, 可以使用typeof关键字

1
2
3
4
5
6
7
8
9
// Good
if (typeof variable === 'undefined') {
// do something
}
// Bad: 直接使用undefined
if (variable == undefined) {
// do something
}

typeof 后面不要加括号

对象

对象应该遵循以下规则:

  • 张开的大括号应该与声明同行
  • 闭合的大括号应该单独一行
  • 每一对属性-值都应该在单独一行,且有一个级别的缩进
  • 属性不用带引号, 后面紧跟着冒号, 冒号与值之前有一个空格
  • 方法前后要有一行空行
  • 相关的属性放到一起, 且后面添加额外的空行,以提高可读性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Good
var object = {
key1: value1,
key2: value2,
func: function() {
// do something
},
key3: value3
};
// Bad: 不正确的缩进
var object = {
key1: value1,
key2: value2
};
// Bad: 函数前后少了空行
var object = {
key1: value1,
key2: value2,
func: function() {
// do something
},
key3: value3
};

参考ES6编程风格

多行定义的对象,最后一个成员以逗号结尾。

1
2
3
4
const b = {
k1: v1,
k2: v2,
};

虽然编译器报警告, 但使用babel(我使用的是6.3.17 (babel-core 6.3.26)版本)编译后, 最后的一个逗号是会去掉的.

函数传参为对象时:

1
2
3
4
5
6
7
8
// Good
doSomething({
key1: value1,
key2: value2
});
// Bad: 所有都放在一行
doSomething({key1: value1, key2: value2});

如果对象只有一个键值对, 写在一行可以接受:

doSomething({key: value1});

变量声明

所有变量应该声明后使用

同时对多个变量声明,只使用一个var, 一行一个变量; 除了第一行,均使用一个级别的缩进

有初始化的的变量在无初始化的前面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Good
var count = 10,
name = "Nicholas",
found = false,
empty;
// Bad: 一行里出现多个声明
var count = 10, name = "Nicholas", found = false, empty;
// Bad: 未初化的变量在前面
var empty,
count = 10,
name = "Nicholas",
found = false;
// Bad: 出现多个声明
var count = 10,
name = "Nicholas";
var found = false,
empty;

注:
ES6的let与const的出现,完全可以取代var. 不是直接在浏览器里写js的话,尽量避免var的使用

原文中认为 = 要对齐, 我认为没必要,因为这样极有可能要填充许多空格:

1
2
3
4
// 实践中我不会这样写,虽然这样真的很好看
var count = 10,
longName = "Nicholas",
found = false,

函数声明

函数先声明后使用

使用函数声明,而不是函数表达式,也不要使用函数构造器

函数体的大括号应该与function关键字同一行; 与包含参数的右括号有一个空格

多个参数时,后一个参数与前面的逗号要有一个空格

函数体的代码要有一个级别的缩进

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Good 函数声明, 且空格/缩进正确
function doSomething(arg1, arg2) {
return arg1 + arg2;
}
// Bad: 不正确的空格
function doSomething (arg1, arg2){
return arg1 + arg2;
}
// Bad: 大括号换行了, 目测这里会引起程序员的战争
function doSomething(arg1, arg2)
{ return arg1 + arg2;
}
// Bad: 函数表达式
var doSomething = function(arg1, arg2) {
return arg1 + arg2;
};
// Bad: 使用函数构造器
var doSomething = new Function("arg1", "arg2", "return arg1 + arg2");

函数里面既有变量声明又有函数声明时, 内部函数的声明应在变量之后.

内部变量的声明最好与外部函数的声明有一行空行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Good
function outer() {
var count = 10,
name = "Nicholas";
function inner() {
// code
}
// code that uses inner()
}
// Bad: 内部函数声明在内部变量声明之前
function outer() {
function inner() {
// code
}
var count = 10,
name = "Nicholas";
// code that uses inner()
}

匿名函数赋值为对象的方法时,fuction关键字与左括号不应该有空格

1
2
3
4
5
6
7
8
9
// Good
object.method = function() {
// code
};
// Bad: 多余的空格
object.method = function () {
// code
};

立即执行函数应该用括号把整个函数的调用包起来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Good
var value = (function() {
// function body
return {
message: "Hi"
}
}());
// Bad: 没有用括号包起来
var value = function() {
// function body
return {
message: "Hi"
}
}();
// Bad: 括号放错位置,没把调用包起来
var value = (function() {
// function body
return {
message: "Hi"
}
})();

在写React组件时, 推荐组件生命周期函数在前, 事件处理等helper函数在后

如果是ES6写法, 定义函数时推荐使用箭头函数, 不要手动绑定this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
clss Component extends React.Component {
static defaultProps = {
}
constructor(props) {
super(props)
this.state = {
}
}
componentWillMount() {
}
componentDidMount() {
}
componentWillReceiveProps(props) {
}
componentDidUpdate() {
}
// render 放在所有lifecycle方法之后
render() {
}
// 事件处理等helper函数放在render后面
// 使用箭头函数, 自动绑定this
onClick = e => {
}
helpRender = () => {
}
}
Fork me on GitHub