My JavaScript Coding Styleguide

本文定义了个人的JavaScript编码规范。


前提说明

行长度

每一行代码严格以80字符为最大长度,即一行包括前后的空格,不得超过80个字符。

由于必定存在一些特殊的原因,导致一条语句的长度超过80,应当按以下原则进行切分:

字符串过长

按一定长度截断字符串,并使用+运算符进行连接。分隔字符串尽量按语音进行,如不要在一个完整的名词中间断开。

特别的,对于HTML片段的拼接,通过缩进,保持和HTML相同的结构:

var html = '' // 此处用一个空字符串,以便整个HTML片段都在新行严格对齐
    + '<article>'
    +     '<h1>Title here</h1>'
    +     '<p>This is a paragraph</p>'
    +     '<footer>Complete</footer>'
    + '</article>';

也可使用数组来进行拼接,相对+运算更容易调整缩进:

var html = [
    '<article>',
        '<h1>Title here</h1>',
        '<p>This is a paragraph</p>',
        '<footer>Complete</footer>',
    '</article>';
];
html = html.join(''); // 注意需要join

函数调用时参数过多

当参数过多,在一行书写函数调用语句会超过80个字符的限制时,应当将每个参数独立写在一行上,并将结束的右括号)独立一行,所有参数增加一个缩进,以控制每行的长度,如:

// 注意每一个参数的缩进
foo(
    aVeryVeryLongArgument,
    anotherVeryLongArgument,
    callback
);

当参数较多,一行一个书写会导致过长时,应当按逻辑对参数进行组合,最经典的是jQuery.format函数,如:

// 将参数分为“模板”和“数据”两块
jQuery.format(
    dateFormatTemplate,
    year, month, date, hour, minute, second
);

// 将参数分为“模板”、“日期”和“时间”
jQuery.format(
    dateFormatTemplate,
    year, month, date, 
    hour, minute, second
);

三元运算符过长

三元运算符由3部分组成,因此其换行应当根据每个部分的长度不同,形成3种不同的情况:

// 无需换行
var result = condition ? resultA : resultB;

// 条件超长的情况
var result = thisIsAVeryVeryLongCondition ?
    resultA : resultB;

// 结果分支超长的情况
var result = condition ?
    thisIsAVeryVeryLongResult :
    resultB;
var result = condition ?
    resultA :
    thisIsAVeryVeryLongResult;

不得出现以下情况:

// 最后一个结果很长,但不建议合并条件和第一分支
// 不要这么干
var result = condition ? resultA :
    thisIsAVeryVeryLongResult;

这种方法会导致语义上的分裂,即条件和分支在一行,另一分支在一行,没有按逻辑进行组织。

过长的逻辑条件组合

当因为较复杂的逻辑条件组合导致80个字符无法满足需求时,考虑将每个条件独立一行,逻辑运算符放置在行尾或行首进行分隔,或将部分逻辑按逻辑组合进行分隔,最终将右括号)与左大括号{放在独立一行,如:

// 注意逻辑运算符前的缩进
if (user.isAuthenticated()
    && user.isInRole('admin')
    && user.hasAuthority('add-admin')
    || user.hasAuthority('delete-admin')
) {
    // Code
}

空格

在特定的位置加上空格有助于代码的可读性,以下位置必须加上空格:

注意,在函数参数列表之前不得加上空格,以下是一个函数的正确声明方式:

function foo(x, y, z) {
    // FunctionBody
}

var foo = function(x, y, z) {
    // FunctionBody
}

对齐和缩进

严格采用4个空格为一次缩进,不得采用TAB作为缩进。在以下情况下必须缩进:

缩进会带来自然的对齐,在缩进之外,不需要额外的对齐:

换行

在以下位置必须换行:

对于因为单行长度超过限制时产生的换行,参考行长度中的策略进行分隔。

除此之外,存在额外的策略:

过长的JSON和数组

如果对象属性较多导致每个属性一行占用空间过大,可以按语义或逻辑进行分组的组织,如:

// 英文-数字的映射
var mapping = {
    one: 1, two: 2, three: 3, four: 4, five: 5,
    six: 6, seven: 7, eight: 8, nine: 9, ten: 10,
    eleven: 11, twelve: 12, thirteen: 13, fourteen: 14, fifteen: 15,
    sixteen: 16, seventeen: 17, eighteen: 18, nineteen: 19, twenty: 20
};

通过5个一组的分组,将每一行控制在合理的范围内,并且按逻辑进行了切分。

对于项目较多的数组,也可以采用相同的方法,如:

// 数字-英文的映射
var mapping = [
    'one', 'two', 'three', 'four', 'five',
    'six', 'seven', 'eight', 'nine', 'ten',
    'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen',
    'sixteen', 'seventeen', 'eighteen', 'nineteen', 'twenty'
];

单行和跨行参数混用

当函数调用时,传递的参数大于或等于2个,且有一个或以上参数跨越多行时,要求每一个参数独立一行,这通常出现在匿名函数或者对象初始化等作为参数时,如setTimeout函数等:

setTimeout(
    function() {
        alert('hello');
    },
    200
);

order.data.read(
    'id=' + me.model.id, 
    function(data) {
        me.attchToModel(data.result);
        callback();
    }, 
    300
);

如果认为每个参数单独一行占用过多的空间,则应当将跨域多行的参数独立出来为一个变量:

function attachDataToModel() {
    me.attchToModel(data.result);
    callback();
}
order.data.read('id=' + me.model.id, attachDataToModel, 300);

数组和对象初始化的混用

严格按照每个对象的起始{和结束}在独立一行的风格书写,如:

var array = [
    {
        // ...
    },
    {
        // ...
    }
];

空行

在代码规范中最容易被人忽略的就是空行。一般来说,代码应该看起来就像一篇如行云流水般的文章, 而不是一篇用连续的用文字堆砌起来的文本。空行就是用来区分相关行和非相关行代码的。

在以下位置必须添加空行:

命名

命名的方法通常有以下几类:

根据不同类型的内容,采用不同的命名法:

命名同时还需要关注语义,如:

语法

变量声明

一个var关键字必须声明一个变量

变量必须即用即声明,不得在函数(或其它形式的代码块)起始位置统一声明所有变量。

字符串

字符串必须使用单引号'

对象和数组

对象和数组优先使用其初始化器({ ... }[ ... ])声明,不要使用new Objectnew Array

如果一个对象的所有属性名均不是保留字,则该对象声明时,所有属性名不得添加引号,这包括属性名是数字的情况。

如果一个对象的属性名有一个或多个是保留字,则该对象声明时,所有属性名必须添加引号。

异常

允许使用异常,但在创建Error对象时,必须明确地传递message参数。

继承

采用jQuery.inherit或相似机制实现继承,不得随意覆盖prototype属性。

声明类的方法时,采用MyClass.prototype.foo = function() {}的形式,不得直接覆盖prototype属性。

其它

修改内置原型

需要修改内置对象的原型时,该代码必须由一个高级别工程师进行Review。

evalwith

当代码中使用evalwith时,该代码必须由一个同级别工程师和一个高级别工程师进行Review。

Related Posts

Xin(Khalil) Zhang 19 January 2015
blog comments powered by Disqus