一份 ECMAScript 2015 的代码规范(上)

以前我们的项目编码风格一直比较混乱。前不久,我们在项目中使用了Babel,吃上了ES2015,顺便配上了ESLint。按照ESLint的rules,我们整理出一份自己的JavaScript代码规范。

配置

npm install --save-dev eslint eslint-config-rgui

然后创建.eslintrc文件,内容如下:

{
    "extends": "rgui",
    "env": {
        "browser": true,
        "node": true
    }
}

具体可以参考ESLint配置

空白

要求使用4个空格作为缩进,禁止使用Tab。✎

indent, no-tabs, no-mixed-spaces-and-tabs

// ✗ bad
function () {
  console.log('Hello');
}

// ✗ bad
function () {
——console.log('Hello');
}

// ✓ good
function () {
    console.log('Hello');
}

强制使用Unix换行符\n,禁止使用Windows换行符\r\n

linebreak-style

禁止使用Unicode字节顺序标记(BOM)。✎

unicode-bom

要求文件末尾有且只有一个空行。✎

eol-last

// ✗ bad
(function (global) {
    // ...stuff...
})(this);

// ✗ bad
(function (global) {
    // ...stuff...
})(this);↵
↵

// ✓ good
(function (global) {
    // ...stuff...
})(this);↵

禁止连续出现多个空行。✎

no-multiple-empty-lines

// ✗ bad
const value = 'Hello';


console.log(value);

// ✓ good
const value = 'Hello';

console.log(value);

禁止块的内边缘出现空行。✎

padded-blocks

// ✗ bad
function bar() {

    console.log(foo);

}

// ✓ good
function bar() {
    console.log(foo);
}

要求运行指令之后必须有一个空行。✎

lines-around-directive

// ✗ bad
'use strict';
let foo;

// ✓ good
'use strict';

let foo;

禁止行尾出现空格。✎

no-trailing-spaces

禁止连续出现多个空格。✎

no-multi-spaces

// ✗ bad
let a =  1;
if(foo   === 'bar') {}
a <<  b
let arr = [1,  2];
a ?  b: c;

// ✓ good
let a = 1;
if(foo === 'bar') {}
a << b
let arr = [1, 2];
a ? b: c;

要求分号、逗号、冒号之后必须有一个空格。✎

semi-spacing, comma-spacing, key-spacing

// ✗ bad
const arr = [1,2,3,4];
const obj = { id:1,name:'Alice' };
foo(a,b,c);
for (let i = 0;i < 10;i++)

// ✓ good
const arr = [1, 2];
const obj = { id: 1, name: 'Alice' };
foo(a, b, c);
for (let i = 0; i < 10; i++)

禁止点号(属性、rest参数、扩展运算符)和单词之间有空格。✎

no-whitespace-before-property, rest-spread-spacing

// ✗ bad
foo. bar. baz();
fn(... args);
[... arr, 4, 5, 6];

// ✓ good
foo.bar.baz();
fn(...args);
[...arr, 4, 5, 6];

要求一元运算符周围没有空格,等号、二元运算符、箭头符号周围有一个空格。✎

space-unary-ops, space-infix-ops, arrow-spacing

// ✗ bad
i ++;
let x=-y*5;
let message='Hello, '+name+'!';
const func=(x)=>{};

// ✓ good
i++;
let x = -y * 5;
let message = 'Hello, ' + name + '!';
const func = (x) => {};

禁止在小括号(表达式、函数)和中括号(数组、属性)内边缘加空格,要求在大括号(对象、单行代码块)内边缘加一个空格。✎

space-in-parens, array-bracket-spacing, computed-property-spacing, object-curly-spacing, block-spacing

// ✗ bad
const num = 3 * ( 2 + 5 );
function hello( name ) {
    console.log( 'Hi,', name );
}
if ( test ) {
    thing();
}

// ✓ good
const num = 3 * (2 + 5);
function hello(name) {
    console.log('Hi,', name);
}
if (test) {
    thing();
}

// ✗ bad
const arr = [ 1, 2, 3 ];
const [ x, y ] = z;
obj[ key ] = 'test';
user[ 'name' ] = 'John';

// ✓ good
const arr = [1, 2, 3];
const [x, y] = z;
obj[key] = 'test';
user['name'] = 'John';

// ✗ bad
const obj = {id: 1, name: 'Alice'};
const {x, y} = z;
function foo() {return true;}
if (foo) { bar = 0;}

// ✓ good
const obj = { id: 1, name: 'Alice' };
const { x, y } = z;
function foo() { return true; }
if (foo) { bar = 0; }

// ✗ bad
product.attr({price: 10.6, tags: ['food', 'sweet']});
product.attr( { price: 10.6, tags: [ 'food', 'sweet' ] } );

// ✓ good
product.attr({ price: 10.6, tags: ['food', 'sweet'] });

要求在大括号前放一个空格。✎

space-before-blocks

// ✗ bad
function test(){
    console.log('test');
}

// ✓ good
function test() {
    console.log('test');
}

// ✗ bad
dog.set('attr',{
    age: '1 year',
    breed: 'Bernese Mountain Dog',
});

// ✓ good
dog.set('attr', {
  age: '1 year',
  breed: 'Bernese Mountain Dog',
});

要求在关键字和小括号之间加一个空格,禁止在函数名和参数列表之间加空格。✎

keyword-spacing, func-call-spacing, space-before-function-paren

保持一致是最好的,你不需要在添加/删除函数名时,考虑要不要添加/删除空格。

// ✗ bad
if(isJedi) {
    fight ();
} else {
    chat ();
}

// ✓ good
if (isJedi) {
    fight();
} else {
    chat();
}

// ✗ bad
function fight () {
    console.log ('Swooosh!');
}
run(function() {
    console.log ('Swooosh!');
});

// ✓ good
function fight() {
    console.log('Swooosh!');
}
run(function () {
    console.log('Swooosh!');
});

禁止出现空块语句或空函数,除非添加一个注释。

no-empty, no-empty-function

// ✗ bad
if (cond) {
}
while (cond) { }

// ✓ good
if (cond) {
    // TODO
}
while (cond) { /* TODO */ }

// ✗ bad
function foo() {}
const foo = function () {};
const foo = () => {};

// ✓ good
function foo() { /* noop */ }
const foo = function () { /* noop */ };
const foo = () => { /* noop */ };

要求大括号风格使用:1tbs(one true brace style)格式,允许单行模式。✎

brace-style

// ✗ bad
function foo()
{
    return true;
}

if (foo) {
    bar();
}
else {
    baz();
}

try
{
    somethingRisky();
} catch(e)
{
    handleError();
}

// ✓ good
function foo() {
    return true;
}

if (foo) {
    bar();
} else {
    baz();
}

try {
    somethingRisky();
} catch(e) {
    handleError();
}

function func() { return true; }
if (foo) { bar(); }

要求遵循大括号约定:multi-or-nest方式,多行时使用大括号,单行时省略大括号。✎

curly

// ✗ bad
if (!obj)
    obj = {
        id: 1,
        name: 'alice',
    };

while (cond)
    if (cond2)
        doSomething();
    else
        doSomethingElse();
if (foo) {
    foo++;
}

while (cond) {
    doSomething();
}

for (let i = 0; i < count; i++) {
    doSomething();
}

// ✓ good
if (!obj) {
    obj = {
        id: 1,
        name: 'alice',
    };
}

while (cond) {
    if (cond2)
        doSomething();
    else
        doSomethingElse();
}

if (foo)
    foo++;

while (cond)
    doSomething();

for (let i = 0; i < count; i++)
    doSomething();

要求单行语句必须换行。✎

nonblock-statement-body-position

// ✗ bad
if (foo) return;
while (cond) doSomething();
for (let i = 0; i < count; i++) doSomething();

// ✓ good
if (foo)
    return;

while (cond)
    doSomething();

for (let i = 0; i < count; i++)
    doSomething();

分号和逗号

强制使用分号,禁止多余的分号。✎

semi, no-extra-semi, no-unexpected-multiline

// ✗ bad
(function () {
    const name = 'Skywalker'
    return name;;
})()

// ✓ good
(function () {
    const name = 'Skywalker';
    return name;
})();

禁止使用行首逗号。✎

comma-style

// ✗ bad
const story = [
    once
  , upon
  , aTime
];

// ✓ good
const story = [
    once,
    upon,
    aTime,
];

禁止使用逗号操作符。

no-sequences

// ✗ bad
foo = doSomething(), val;
if (doSomething(), !!test);
while (val = foo(), val < 42);

// ✓ good
doSomething();
foo = val;
if (!!test);
while ((val = foo()) < 42);

要求多行使用拖尾逗号,禁止单行使用拖尾逗号。✎

comma-dangle

这会使git diffs更简洁,使编辑器的上下移动快捷键更方便。不用担心IE8会报错,Babel等编译器会自动去除拖尾逗号。

// ✗ bad - git diff without trailing comma
const hero = {
     firstName: 'Florence',
-    lastName: 'Nightingale'
+    lastName: 'Nightingale',
+    inventorOf: ['coxcomb chart', 'modern nursing']
};

// ✓ good - git diff with trailing comma
const hero = {
     firstName: 'Florence',
     lastName: 'Nightingale',
+    inventorOf: ['coxcomb chart', 'modern nursing'],
};

// ✗ bad
const hero = {
  firstName: 'Dana',
  lastName: 'Scully'
};
const heroes = [
  'Batman',
  'Superman'
];

// ✓ good
const hero = {
  firstName: 'Dana',
  lastName: 'Scully',
};
const heroes = [
  'Batman',
  'Superman',
];

// ✗ bad
const hero = { firstName, lastName, };
const arr = [1, 2, 3, ];

// ✓ good
const hero = { firstName, lastName };
const arr = [1, 2, 3];

字符串

要求使用单引号包裹字符串,在需要插值或换行时才使用反引号,在内部单引号需要转义时才使用双引号。✎

quotes

// ✗ bad
const hello = "Hello, Bob!";
const element = `<div class="box"></div>`;
const message = 'I don\'t like quotes.';

// ✓ good
const hello = 'Hello, Bob!';
const element = `<div class="${className}"></div>`;
const message = "I don't like quotes.";

禁止不必要的字符拼接。

no-useless-concat

// ✗ bad
const a = 'some' + 'string';
const a = '1' + '0';

// ✓ good
const c = 'somestring';
const a = '10';

禁止使用不必要的转义符。

no-useless-escape

// ✗ bad
const foo = '\"This\" \i\s \'quoted\'';

// ✓ good
const foo = '"This" is \'quoted\'';
const foo = `"This" is 'quoted'`;

禁止使用多行字符串。

no-multi-str

// ✗ bad
const message = 'Hello \
                 world';
// ✓ good
const message = `Hello
                world`;

尽量使用模板字符串,禁止在模板字符串的大括号周围加空格。✎

prefer-template, template-curly-spacing

// ✗ bad
return 'How are you, ' + name + '?';
return ['How are you, ', name, '?'].join();
return `How are you, ${ name }?`;

// ✓ good
return `How are you, ${name}?`;

对象和属性

要求点操作符和属性放在同一行。✎

dot-location

// ✗ bad
$('#items').
    find('.selected').
    highlight().
    end().
    find('.open').
    updateCount();

// ✓ good
$('#items')
    .find('.selected')
    .highlight()
    .end()
    .find('.open')
    .updateCount();
$('#items').find('.selected').highlight().end().find('.open').updateCount();

// ✗ bad
const p = promise.
    then(function() {
        // code
    }).
    catch(function() {
        // code
    });

// ✓ good
const p = promise.then(function() {
    // code
}).catch(function() {
    // code
});

要求尽可能使用点号,且不回避关键字。✎

dot-notation

// ✗ bad
const result = luke['jedi'];

// ✓ good
const result = luke.jedi;
const result = luke.class;
const result = luke[key];

禁止使用不必要的计算属性。✎

no-useless-computed-key

// ✗ bad
const user = { ['name']: 'John Doe' };
// ✓ good
const user = { name: 'John Doe' };

要求使用对象属性的简写语法。✎

object-shorthand

// ✗ bad
const atom = {
    value: value,
    add: function (value) {
        return atom.value + value;
    },
};

// ✓ good
const atom = {
    value,
    add(value) {
        return atom.value + value;
    },
};

要求只给对象中需要的属性名加引号。✎

quote-props

// ✗ bad
const bad = {
  'foo': 3,
  'bar': 4,
  '>5,
};

// ✓ good
const good = {
  foo: 3,
  bar: 4,
  '>5,
};

运算符

强制使用=====,禁止使用==!=

eqeqeq

该规则旨在消除非类型安全的相等操作符。例如以下语句均被认为是true

  • [] == false
  • [] == ![]
  • 3 == "03"

// ✗ bad
if (a == b)
if (foo == true)
if (bananas != 1)
if (value == undefined)
if (typeof foo == 'undefined')
if ('hello' != 'world')
if (0 == 0)
if (true == true)
if (foo == null)

// ✓ good
if (a === b)
if (foo === true)
if (bananas !== 1)
if (value === undefined)
if (typeof foo === 'undefined')
if ('hello' !== 'world')
if (0 === 0)
if (true === true)
if (foo === null)

禁止出现Yoda条件,除非是在范围中使用。✎

yoda

// ✗ bad
if ('red' === color)
if (true == flag)
if (-1 < str.indexOf(substr))

// ✓ good
if (color === 'red')
if (flag)
if (0 <= x && x < 1)

要求把换行符放在运算符的前面。

operator-linebreak

// ✗ bad
let fullHeight = borderTop +
                 innerHeight +
                 borderBottom;
if (someCodition ||
    otherCondition) {
        // ...
}

// ✓ good
let fullHeight = borderTop
               + innerHeight
               + borderBottom;
if (someCodition
    || otherCondition) {
       // ...
}


相关阅读:

一份 ECMAScript 2015 的代码规范(中)

一份 ECMAScript 2015 的代码规范(下)

本文来自网易实践者社区,经作者赵雨森授权发布。