我的javascript代码书写风格

这份风格清单还会继续更新,它的主要依据有以下几点:

  • 易于git diff
  • 少敲代码,键盘按键个数少、次数少和距离舒适
  • 易于阅读,不故意加入反人类的风格,比如“逗号前置”

1. 以换行而非分号结束语句

var a = 1
var b = 10

之所以这样做的原因,有两个:

  1. javascript并不一定以分号作为语句的结束,虽然确实可以这样做,但是换行也可以做到,光是 “可以加分号但是大家都不加” 的语言就有:Go, Scala, Ruby, Python, Swift, Groovy...,所以我觉得写成没有分号的语句更好看。
  2. 不以分号结束,有利于后期新增代码时,直接往下加即可。比如.pipe,如果要在之后再增加一个.pipe,只需要换行以后继续写.pipe即可,而不需要删除分号。在git中不会提示有分号那一行也被修改,有利于git commits的美观。

没有分号也让代码量变小,当然不利于Minify,但是一般Minify都是用工具做到的,都会自动加分号。

但是在特殊情况下,换行结束语句有问题:

Array.prototype.log = function() {
    console.log(this)
}
[1, 2, 3].log()

上面这段代码会报错,为什么呢?因为当使用function(){}[]这种形式的代码时,函数会被立即执行,这也是个坑,函数执行完之后得到一个返回值undefined,然后再执行undefined.log()赋值给Array.prototype.log,undefined.log()的地方自然就会报错。解决方案是:

在句首是 ( [ / + - 时在前面加分号

不过既然如此,那么在我的风格中,就应该禁止以([/+-作为句首,一般使用这些操作符作为行首都是想实现一些直接的运算,比如上面那段报错的代码,这虽然看上去简便了很多,但实际上这种运算在实践中意义不是很大,更多的是用在测试中。

实际上,这个问题的本质是对js语句的理解。一个语句会以怎样的方式开始?又会以怎样的方式结束?前一个问题理解透之后,再理解后一个问题作为补充。

javascript语句

  1. 表达式语句:a=b+c, d()
  2. 复合语句和空语句:{}, ;
  3. 声明语句:var, function
  4. 条件判断语句:if, switch
  5. 循环语句:for, while
  6. 跳转语句:break, continue, return, throw
  7. width、debugger和use strict

上面这些就是javascript的语句。大部分语句的开始都不会带来不写分号的问题,但是必须注意表达式语句。

以变量作为表达式语句的开头

例如:

a = 1
b = a + 1
c.log()
d ++
Math.abs(e)
window.log(f)

你可以看到,凡是以变量开头的表达式语句都不会造成上述分号问题。但是,如果像最开始的那段代码,先通过运算、操作、命令后在进行操作的类表达式,则需要谨慎:

('a' + 'b').split('')
[2, 4].join('')
(function(){})()

等等,这类语句也非常像表达式语句,但是它们的前提是先要进行运算后在进行操作。面对这类表达式语句,应该先赋值给变量后,在进行变量表达式操作:

var a = 'a' + 'b'
a.split('')
var b = [2, 4]
b.join('')
var c = function() {}
c()

当以变量开始语句时,就不会在发生上述问题。但是有的时候,你并不希望产生一个多余的变量,这种情况下,最好的办法就是在这种复杂表达式前面加分号;

几乎所有的分号问题,都是因为使用了复杂的表达式语句产生的。如果遵循了上面我提到的先变量赋值再进行简单表达式语句的话,就可以有效避免这个问题。

2. 用逗号分开的变量、参数、表达式,逗号后面空一格

var x, y
function a(x, y) {}
a(12, 14)
var [m, n, l] = [j, ...k]
stream.on('end', () => {})

3. 使用===而非==,!==同理,只有当希望发生类型转化时,才用==

if(typeof a === 'undefined') {}
if(0 == '0') {}

全等会判断数据类型,比如null和false就不全等,0和false也不全等。

4. 使用''引用字符串,使用``引用带变量的字符串,仅在html,json等有必要的地方使用""

var a = 'k'
var b = 'This is my first dog!'
var c = `Do you see a ${a} on the wall?`

之所以不适用双引号,主要是考虑打双引号要一只手按住shift键,另一只手按引号键。但是html中双引号更好,因为一些dom操作会使用双引号来添加属性。有些地方只能使用双引号,使用单引号还会引起一些错误,比如使用js去写一段嵌入式的shell时,这个时候,就必须在shell命令内部使用双引号。

5. '{'前面有一个空格,函数的'('前面不要空格,其他'('要一个空格,')'后面要有一个空格,'}'后面应该换行,但如果后面是')'就不换行不留空格

if (a === 10) {}
else {}
arr.forEach(item => {})

其实{前面有空格,和下面的6也有关系,因为{前面总是那种后面需要跟空格的符号。但是也有例外,就是声明一个类的时候:class MyClass {},这种情况下就体现了这条规则是必须的。

(跟在函数(或方法函数)后面,作为参数列表时,和函数名之间不需要有空格;但是跟在if, while等语句关键字后面时,加上一个空格。

6. =, ==, !=, ===, !==, &&, ||, =>前后都有空格,但!后面不空格

var a = 10
if(a === 20) {}
setTimeout(() => {},1000)
if(!b) {}

7. ()内部紧贴表达式部分不留空格

if(a === b) {}
function c(go, to) {}

即使是使用了多层括号,也应该考虑通过换行的形式,而非空格的形式来处理。

8. 命名:普通变量、函数用驼峰命名,类用大写开头的驼峰命名,键名用连字符隔开的命名

var yourName = 'tom'
function runTask() {}
class MyTask {}
whiteHouse.set('left-color', 'grey')

9. 冒号':'前面无需空格,后面要有一个空格

{
    age: 10,
}

10. 以逗号结尾的换行变量组中,最后一个变量加上逗号

var obj = {
    name: 'Nick',
    age: 10,
    sex: 'man',
}
function factory(
    arg1,
    arg2 = 10,
) {}

这样做也是和第一条有点像,如果要继续添加变量,只需要换行即可,不需要在最后一行添加一个逗号。声明变量不用逗号隔开的形式,而是全部用声明关键字换行声明,一行一个。

有些风格喜欢“逗号前置”的形式来处理这个点,比如:

var a = 10
    , b = 20
    , c = 30
var d, e, f

这样的好处是通过逗号分离的多个变量声明即使删掉最后一个,也不会造成错误。但是这种风格给人反人类的感觉,不喜欢,所以我的声明遵循11条。

11.声明时一个变量占一行,使用逗号一次性声明多个变量仅用在未赋值的变量,并且这些未赋值的变量必须放在一起,且至于一组声明的最后

var a = 1
var b = 2
var c, d, f

这样做的好处避免了上文提到的删掉最后一个声明变量时引起的问题。

12.if条件语句的中括号,仅在后跟return时可以省略;单条if...else赋值语句应该用?:代替

function() {
  ...
  if(xxx) return
  ...
  if(xxx) a = 1
  else a = 0
  a = xxx ? 1 : 0
  ...
}

13.代码缩进和tab使用两个空格

理由非常简单,tab不能直接使用\t,因为在不同的环境下,缩进距离会不一样,不使用4个空格是因为在一些条件下,我们需要手动输入空格来表示缩进,手动输入四个空格跟两个空格真是的不一样的体验。

 

2016-12-05

已有1条评论
  1. […] 在《我的javascript代码风格》中,我给的第一条风格就是“以换行结束一句语句,而非分号”。其实这个表达是错误的,它真实的表达应该是“不使用分号作为句尾”,也就是说它隐含了两层意思:1.句尾无分号;2.要正确处理语句结束的问题。在经过几个月的实践之后,今天就来谈谈彻底放弃使用分号作为句尾的感受。 […]