from airbnb translation https://github.com/lin-123/javascript
References
-
2.1 所有的赋值都用
const
,避免使用var
. eslint:prefer-const
,no-const-assign
Why? 因为这个确保你不会改变你的初始值,重复引用会导致bug和代码难以理解
// bad var a = 1; var b = 2; // good const a = 1; const b = 2;
-
2.2 如果你一定要对参数重新赋值,那就用
let
,而不是var
. eslint:no-var
Why? 因为
let
是块级作用域,而var
是函数级作用域// bad var count = 1; if (true) { count += 1; } // good, use the let. let count = 1; if (true) { count += 1; }
Objects
-
3.1 使用字面值创建对象. eslint:
no-new-object
// bad const item = new Object(); // good const item = {};
-
3.2 当创建一个带有动态属性名的对象时,用计算后属性名
Why? 这可以使你将定义的所有属性放在对象的一个地方.
function getKey(k) { return `a key named ${k}`; } // bad const obj = { id: 5, name: 'San Francisco', }; obj[getKey('enabled')] = true; // good getKey('enabled')是动态属性名 const obj = { id: 5, name: 'San Francisco', [getKey('enabled')]: true, };
-
3.4 用属性值缩写. eslint:
object-shorthand
Why? 这样写的更少且更可读
const lukeSkywalker = 'Luke Skywalker'; // bad const obj = { lukeSkywalker: lukeSkywalker, }; // good const obj = { lukeSkywalker, };
-
3.5 将你的所有缩写放在对象声明的开始.
Why? 这样也是为了更方便的知道有哪些属性用了缩写.
const anakinSkywalker = 'Anakin Skywalker'; const lukeSkywalker = 'Luke Skywalker'; // bad const obj = { episodeOne: 1, twoJediWalkIntoACantina: 2, lukeSkywalker, episodeThree: 3, mayTheFourth: 4, anakinSkywalker, }; // good const obj = { lukeSkywalker, anakinSkywalker, episodeOne: 1, twoJediWalkIntoACantina: 2, episodeThree: 3, mayTheFourth: 4, };
-
3.6 只对那些无效的标示使用引号
''
. eslint:quote-props
Why? 通常我们认为这种方式主观上易读。他优化了代码高亮,并且页更容易被许多JS引擎压缩。
// bad const bad = { 'foo': 3, 'bar': 4, 'data-blah': 5, }; // good const good = { foo: 3, bar: 4, 'data-blah': 5, };
- 3.8 对象浅拷贝时,更推荐使用扩展运算符[就是
...
运算符],而不是Object.assign
。获取对象指定的几个属性时,用对象的rest解构运算符[也是...
运算符]更好。- 这一段不太好翻译出来, 大家看下面的例子就懂了。.
// very bad
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ
delete copy.a; // so does this
// bad
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
// good es6扩展运算符 ...
const original = { a: 1, b: 2 };
// 浅拷贝
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
// rest 赋值运算符
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
Arrays
-
4.1 用字面量赋值。 eslint:
no-array-constructor
// bad const items = new Array(); // good const items = [];
-
4.2 用Array#push 代替直接向数组中添加一个值。
const someStack = []; // bad someStack[someStack.length] = 'abracadabra'; // good someStack.push('abracadabra');
-
4.3 用扩展运算符做数组浅拷贝,类似上面的对象浅拷贝
// bad const len = items.length; const itemsCopy = []; let i; for (i = 0; i < len; i += 1) { itemsCopy[i] = items[i]; } // good const itemsCopy = [...items];
-
4.4 用
...
运算符而不是Array.from
来将一个可迭代的对象转换成数组。const foo = document.querySelectorAll('.foo'); // good const nodes = Array.from(foo); // best const nodes = [...foo];
-
4.5 用
Array.from
去将一个类数组对象转成一个数组。const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 }; // bad const arr = Array.prototype.slice.call(arrLike); // good const arr = Array.from(arrLike);
-
4.6 用
Array.from
而不是...
运算符去做map遍历。 因为这样可以避免创建一个临时数组。// bad const baz = [...foo].map(bar); // good const baz = Array.from(foo, bar);
Destructuring
-
5.1 用对象的解构赋值来获取和使用对象某个或多个属性值。 eslint:
prefer-destructuring
Why? 解构保存了这些属性的临时值/引用
// bad function getFullName(user) { const firstName = user.firstName; const lastName = user.lastName; return `${firstName} ${lastName}`; } // good function getFullName(user) { const { firstName, lastName } = user; return `${firstName} ${lastName}`; } // best function getFullName({ firstName, lastName }) { return `${firstName} ${lastName}`; }
-
5.2 用数组解构.
const arr = [1, 2, 3, 4]; // bad const first = arr[0]; const second = arr[1]; // good const [first, second] = arr;
-
5.3 多个返回值用对象的解构,而不是数组解构。
Why? 你可以在后期添加新的属性或者变换变量的顺序而不会打破原有的调用
// bad function processInput(input) { // 然后就是见证奇迹的时刻 return [left, right, top, bottom]; } // 调用者需要想一想返回值的顺序 const [left, __, top] = processInput(input); // good function processInput(input) { // oops, 奇迹又发生了 return { left, right, top, bottom }; } // 调用者只需要选择他想用的值就好了 const { left, top } = processInput(input);
Strings
-
6.1 对string用单引号
''
。 eslint:quotes
// bad const name = "Capt. Janeway"; // bad - 样例应该包含插入文字或换行 const name = `Capt. Janeway`; // good const name = 'Capt. Janeway';
-
6.2 超过100个字符的字符串不应该用string串联成多行。
Why? 被折断的字符串工作起来是糟糕的而且使得代码更不易被搜索。
// bad const errorMessage = 'This is a super long error that was thrown because \ of Batman. When you stop to think about how Batman had anything to do \ with this, you would get nowhere \ fast.'; // bad const errorMessage = 'This is a super long error that was thrown because ' + 'of Batman. When you stop to think about how Batman had anything to do ' + 'with this, you would get nowhere fast.'; // good const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';
-
6.3 用字符串模板而不是字符串拼接来组织可编程字符串。 eslint:
prefer-template
template-curly-spacing
Why? 模板字符串更具可读性、语法简洁、字符串插入参数。
// bad function sayHi(name) { return 'How are you, ' + name + '?'; } // bad function sayHi(name) { return ['How are you, ', name, '?'].join(); } // bad function sayHi(name) { return `How are you, ${ name }?`; } // good function sayHi(name) { return `How are you, ${name}?`; }
- 6.4 永远不要在字符串中用
eval()
,他就是潘多拉盒子。 eslint:no-eval
-
6.5 不要使用不必要的转义字符。eslint:
no-useless-escape
Why? 反斜线可读性差,所以他们只在必须使用时才出现哦
// bad const foo = '\'this\' \i\s \"quoted\"'; // good const foo = '\'this\' is "quoted"'; //best const foo = `my name is '${name}'`;
Functions
-
7.5 不要用
arguments
命名参数。他的优先级高于每个函数作用域自带的arguments
对象, 这会导致函数自带的arguments
值被覆盖// bad function foo(name, options, arguments) { // ... } // good function foo(name, options, args) { // ... }
-
7.6 不要使用
arguments
,用rest语法...
代替。 eslint:prefer-rest-params
Why?
...
明确你想用那个参数。而且rest参数是真数组,而不是类似数组的arguments
// bad function concatenateAll() { const args = Array.prototype.slice.call(arguments); return args.join(''); } // good function concatenateAll(...args) { return args.join(''); }
-
7.7 用默认参数语法而不是在函数里对参数重新赋值。
// really bad function handleThings(opts) { // 不, 我们不该改arguments // 第二: 如果 opts 的值为 false, 它会被赋值为 {} // 虽然你想这么写, 但是这个会带来一些细微的bug opts = opts || {}; // ... } // still bad function handleThings(opts) { if (opts === void 0) { opts = {}; } // ... } // good function handleThings(opts = {}) { // ... }
-
7.9 把默认参数赋值放在最后
// bad function handleThings(opts = {}, name) { // ... } // good function handleThings(name, opts = {}) { // ... }
-
7.10 不要用函数构造器创建函数。 eslint:
no-new-func
Why? 以这种方式创建函数将类似于字符串 eval(),这会打开漏洞。
// bad var add = new Function('a', 'b', 'return a + b'); // still bad var subtract = Function('a', 'b', 'return a - b');
-
7.12 不要改参数. eslint:
no-param-reassign
Why? 操作参数对象对原始调用者会导致意想不到的副作用。 就是不要改参数的数据结构,保留参数原始值和数据结构。
// bad function f1(obj) { obj.key = 1; }; // good function f2(obj) { const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1; };
-
7.13 不要对参数重新赋值。 eslint:
no-param-reassign
Why? 参数重新赋值会导致意外行为,尤其是对
arguments
。这也会导致优化问题,特别是在V8里// bad function f1(a) { a = 1; // ... } function f2(a) { if (!a) { a = 1; } // ... } // good function f3(a) { const b = a || 1; // ... } function f4(a = 1) { // ... }
-
7.15 调用或者书写一个包含多个参数的函数应该想这个指南里的其他多行代码写法一样: 每行值包含一个参数,每行逗号结尾。
// bad function foo(bar, baz, quux) { // ... } // good 缩进不要太过分 function foo( bar, baz, quux, ) { // ... } // bad console.log(foo, bar, baz); // good console.log( foo, bar, baz, );
Modules
-
10.2 不要用import通配符, 就是
*
这种方式Why? 这确保你有单个默认的导出
// bad import * as AirbnbStyleGuide from './AirbnbStyleGuide'; // good import AirbnbStyleGuide from './AirbnbStyleGuide';
-
10.3 不要直接从import中直接export
Why? 虽然一行是简洁的,有一个明确的方式进口和一个明确的出口方式来保证一致性。
// bad // filename es6.js export { es6 as default } from './AirbnbStyleGuide'; // good // filename es6.js import { es6 } from './AirbnbStyleGuide'; export default es6;
-
10.4 一个路径只 import 一次。
eslint:no-duplicate-imports
Why? 从同一个路径下import多行会使代码难以维护
// bad import foo from 'foo'; // … some other imports … // import { named1, named2 } from 'foo'; // good import foo, { named1, named2 } from 'foo'; // good import foo, { named1, named2, } from 'foo';
-
10.5 不要导出可变的东西
eslint:import/no-mutable-exports
Why? 变化通常都是需要避免,特别是当你要输出可变的绑定。虽然在某些场景下可能需要这种技术,但总的来说应该导出常量。
// bad let foo = 3; export { foo } // good const foo = 3; export { foo }
-
10.6 在一个单一导出模块里,用
export default
更好。
eslint:import/prefer-default-export
Why? 鼓励使用更多文件,每个文件只做一件事情并导出,这样可读性和可维护性更好。
// bad export function foo() {} // good export default function foo() {}
-
10.7
import
放在其他所有语句之前。
eslint:import/first
Why? 让
import
放在最前面防止意外行为。// bad import foo from 'foo'; foo.init(); import bar from 'bar'; // good import foo from 'foo'; import bar from 'bar'; foo.init();
-
10.8 多行import应该缩进,就像多行数组和对象字面量
Why? 花括号与样式指南中每个其他花括号块遵循相同的缩进规则,逗号也是。
// bad import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path'; // good import { longNameA, longNameB, longNameC, longNameD, longNameE, } from 'path';
教学项目中不换行,选前者
Variables
-
13.3
const
放一起,let
放一起Why? 在你需要分配一个新的变量, 而这个变量依赖之前分配过的变量的时候,这种做法是有帮助的
// bad let i, len, dragonball, items = getItems(), goSportsTeam = true; // bad let i; const items = getItems(); let dragonball; const goSportsTeam = true; let len; // good const goSportsTeam = true; const items = getItems(); let dragonball; let i; let length;
-
13.5 不要使用链式变量分配。 eslint:
no-multi-assign
Why? 链接变量分配创建隐式全局变量。
// bad (function example() { // JavaScript 将这一段解释为 // let a = ( b = ( c = 1 ) ); // let 只对变量 a 起作用; 变量 b 和 c 都变成了全局变量 let a = b = c = 1; }()); console.log(a); // undefined console.log(b); // 1 console.log(c); // 1 // good (function example() { let a = 1; let b = a; let c = a; }()); console.log(a); // undefined console.log(b); // undefined console.log(c); // undefined // `const` 也是如此
-
13.6 不要使用一元自增自减运算符(
++
,--
). eslintno-plusplus
Why? 根据eslint文档,一元增量和减量语句受到自动分号插入的影响,并且可能会导致应用程序中的值递增或递减的无声错误。 使用
num + = 1
而不是num ++
或num ++
语句来表达你的值也是更有表现力的。 禁止一元增量和减量语句还会阻止您无意地预增/预减值,这也会导致程序出现意外行为。// bad let array = [1, 2, 3]; let num = 1; num++; --num; let sum = 0; let truthyCount = 0; for(let i = 0; i < array.length; i++){ let value = array[i]; sum += value; if (value) { truthyCount++; } } // good let array = [1, 2, 3]; let num = 1; num += 1; num -= 1; const sum = array.reduce((a, b) => a + b, 0); const truthyCount = array.filter(Boolean).length;
-
13.7 在赋值的时候避免在
=
前/后换行。 如果你的赋值语句超出max-len
, 那就用小括号把这个值包起来再换行。 eslintoperator-linebreak
.Why? 在
=
附近换行容易混淆这个赋值语句。// bad const foo = superLongLongLongLongLongLongLongLongFunctionName(); // bad const foo = 'superLongLongLongLongLongLongLongLongString'; // good const foo = ( superLongLongLongLongLongLongLongLongFunctionName() ); // good const foo = 'superLongLongLongLongLongLongLongLongString';
-
13.8 不允许有未使用的变量。 eslint:
no-unused-vars
Why? 一个声明了但未使用的变量更像是由于重构未完成产生的错误。这种在代码中出现的变量会使阅读者迷惑。
// bad var some_unused_var = 42; // 写了没用 var y = 10; y = 5; // 变量改了自己的值,也没有用这个变量 var z = 0; z = z + 1; // 参数定义了但未使用 function getX(x, y) { return x; } // good function getXPlusY(x, y) { return x + y; } var x = 1; var y = a + 2; alert(getXPlusY(x, y)); // 'type' 即使没有使用也可以可以被忽略, 因为这个有一个 rest 取值的属性。 // 这是从对象中抽取一个忽略特殊字段的对象的一种形式 var { type, ...coords } = data; // 'coords' 现在就是一个没有 'type' 属性的 'data' 对象
Comparison Operators & Equality
- 15.1 用
===
和!==
而不是==
和!=
. eslint:eqeqeq
-
15.6 三元表达式不应该嵌套,通常是单行表达式。
eslint rules:
no-nested-ternary
.// bad const foo = maybe1 > maybe2 ? "bar" : value1 > value2 ? "baz" : null; // better const maybeNull = value1 > value2 ? 'baz' : null; const foo = maybe1 > maybe2 ? 'bar' : maybeNull; // best const maybeNull = value1 > value2 ? 'baz' : null; const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
-
15.7 避免不需要的三元表达式
eslint rules:
no-unneeded-ternary
.// bad const foo = a ? a : b; const bar = c ? true : false; const baz = c ? false : true; // good const foo = a || b; const bar = !!c; const baz = !c;
-
15.8 用圆括号来混合这些操作符。 只有当标准的算术运算符(
+
,-
,*
, &/
), 并且它们的优先级显而易见时,可以不用圆括号括起来。 eslint:no-mixed-operators
Why? 这提高了可读性,并且明确了开发者的意图
// bad const foo = a && b < 0 || c > 0 || d + 1 === 0; // bad const bar = a ** b - 5 % d; // bad // 别人会陷入(a || b) && c 的迷惑中 if (a || b && c) { return d; } // good const foo = (a && b < 0) || c > 0 || (d + 1 === 0); // good const bar = (a ** b) - (5 % d); // good if (a || (b && c)) { return d; } // good const bar = a + b / c * d;
Blocks
-
16.2
if
表达式的else
和if
的关闭大括号在一行。 eslint:brace-style
// bad if (test) { thing1(); thing2(); } else { thing3(); } // good if (test) { thing1(); thing2(); } else { thing3(); }
-
16.3 如果
if
语句中总是需要用return
返回, 那后续的else
就不需要写了。if
块中包含return
, 它后面的else if
块中也包含了return
, 这个时候就可以把return
分到多个if
语句块中。 eslint:no-else-return
// bad function foo() { if (x) { return x; } else { return y; } } // bad function cats() { if (x) { return x; } else if (y) { return y; } } // bad function dogs() { if (x) { return x; } else { if (y) { return y; } } } // good function foo() { if (x) { return x; } return y; } // good function cats() { if (x) { return x; } if (y) { return y; } } // good function dogs(x) { if (x) { if (z) { return y; } } else { return z; } }
Control Statements
-
17.1 当你的控制语句(
if
,while
等)太长或者超过最大长度限制的时候, 把每一个(组)判断条件放在单独一行里。 逻辑操作符放在行首。Why? 把逻辑操作符放在行首是让操作符的对齐方式和链式函数保持一致。这提高了可读性,也让复杂逻辑更容易看清楚。
// bad if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) { thing1(); } // bad if (foo === 123 && bar === 'abc') { thing1(); } // bad if (foo === 123 && bar === 'abc') { thing1(); } // bad if ( foo === 123 && bar === 'abc' ) { thing1(); } // good if ( foo === 123 && bar === 'abc' ) { thing1(); } // good if ( (foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening() ) { thing1(); } // good if (foo === 123 && bar === 'abc') { thing1(); }
-
17.2 不要用选择操作符代替控制语句。
// bad !isRunning && startRunning(); // good if (!isRunning) { startRunning(); }
不做强制要求
Whitespace
-
19.1 tab用两个空格. eslint:
indent
// bad function foo() { ∙∙∙∙const name; } // bad function bar() { ∙const name; } // good function baz() { ∙∙const name; }
-
19.2 在大括号前空一格。 eslint:
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', });
-
19.3 在控制语句(
if
,while
等)的圆括号前空一格。在函数调用和定义时,参数列表和函数名之间不空格。 eslint:keyword-spacing
// bad if(isJedi) { fight (); } // good if (isJedi) { fight(); } // bad function fight () { console.log ('Swooosh!'); } // good function fight() { console.log('Swooosh!'); }
-
19.4 用空格来隔开运算符。 eslint:
space-infix-ops
// bad const x=y+5; // good const x = y + 5;
-
19.5 文件结尾空一行. eslint:
eol-last
// bad import { es6 } from './AirbnbStyleGuide'; // ... export default es6;
// bad import { es6 } from './AirbnbStyleGuide'; // ... export default es6;↵ ↵
// good import { es6 } from './AirbnbStyleGuide'; // ... export default es6;↵
-
19.6 当出现长的方法链(>2个)时用缩进。用点开头强调该行是一个方法调用,而不是一个新的语句。eslint:
newline-per-chained-call
no-whitespace-before-property
// bad $('#items').find('.selected').highlight().end().find('.open').updateCount(); // bad $('#items'). find('.selected'). highlight(). end(). find('.open'). updateCount(); // good $('#items') .find('.selected') .highlight() .end() .find('.open') .updateCount(); // bad const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true) .attr('width', (radius + margin) * 2).append('svg:g') .attr('transform', `translate(${radius + margin},${radius + margin})`) .call(tron.led); // good const leds = stage.selectAll('.led') .data(data) .enter().append('svg:svg') .classed('led', true) .attr('width', (radius + margin) * 2) .append('svg:g') .attr('transform', `translate(${radius + margin},${radius + margin})`) .call(tron.led); // good const leds = stage.selectAll('.led').data(data);
-
19.7 在一个代码块后下一条语句前空一行。
// bad if (foo) { return bar; } return baz; // good if (foo) { return bar; } return baz; // bad const obj = { foo() { }, bar() { }, }; return obj; // good const obj = { foo() { }, bar() { }, }; return obj; // bad const arr = [ function foo() { }, function bar() { }, ]; return arr; // good const arr = [ function foo() { }, function bar() { }, ]; return arr;
-
19.8 不要用空白行填充块。 eslint:
padded-blocks
// bad function bar() { console.log(foo); } // also bad if (baz) { console.log(qux); } else { console.log(foo); } // good function bar() { console.log(foo); } // good if (baz) { console.log(qux); } else { console.log(foo); }
-
19.9 圆括号里不要加空格。 eslint:
space-in-parens
// bad function bar( foo ) { return foo; } // good function bar(foo) { return foo; } // bad if ( foo ) { console.log(foo); } // good if (foo) { console.log(foo); }
-
19.10 方括号里不要加空格。看示例。 eslint:
array-bracket-spacing
// bad const foo = [ 1, 2, 3 ]; console.log(foo[ 0 ]); // good, 逗号分隔符还是要空格的 const foo = [1, 2, 3]; console.log(foo[0]);
-
19.11 花括号里加空格。 eslint:
object-curly-spacing
// bad const foo = {clark: 'kent'}; // good const foo = { clark: 'kent' };
19.12 避免一行代码超过120个字符(包含空格)。
-
注意: 对于上面——strings--line-length,长字符串不受此规则限制,不应分解。 eslint:
max-len
Why? 这样确保可读性和可维护性
// bad const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy; // bad $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.')); // good const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy; // good $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' }, }) .done(() => console.log('Congratulations!')) .fail(() => console.log('You have failed this city.'));
-
19.13 作为语句的花括号内也要加空格 ——
{
后和}
前都需要空格。 eslint:block-spacing
// bad function foo() {return true;} if (foo) { bar = 0;} // good function foo() { return true; } if (foo) { bar = 0; }
-
19.14
,
前不要空格,,
后需要空格。 eslint:comma-spacing
// bad var foo = 1,bar = 2; var arr = [1 , 2]; // good var foo = 1, bar = 2; var arr = [1, 2];
-
19.15 计算属性内要空格。参考上述花括号和中括号的规则。 eslint:
computed-property-spacing
// bad obj[foo ] obj[ 'foo'] var x = {[ b ]: a} obj[foo[ bar ]] // good obj[foo] obj['foo'] var x = { [b]: a } obj[foo[bar]]
-
19.16 调用函数时,函数名和小括号之间不要空格。 eslint:
func-call-spacing
// bad func (); func (); // good func();
-
19.17 在对象的字面量属性中,
key
value
之间要有空格。 eslint:key-spacing
// bad var obj = { "foo" : 42 }; var obj2 = { "foo":42 }; // good var obj = { "foo": 42 };
- 19.18 行末不要空格。 eslint:
no-trailing-spaces
-
19.19 避免出现多个空行。 在文件末尾只允许空一行。 eslint:
no-multiple-empty-lines
// bad var x = 1; var y = 2; // good var x = 1; var y = 2;
Commas
-
20.1 不要前置逗号。 eslint:
comma-style
// bad const story = [ once , upon , aTime ]; // good const story = [ once, upon, aTime, ]; // bad const hero = { firstName: 'Ada' , lastName: 'Lovelace' , birthYear: 1815 , superPower: 'computers' }; // good const hero = { firstName: 'Ada', lastName: 'Lovelace', birthYear: 1815, superPower: 'computers', };
-
20.2 额外结尾逗号: 要 eslint:
comma-dangle
Why? 这导致git diffs更清洁。 此外,像Babel这样的转换器会删除转换代码中的额外的逗号,这意味着你不必担心旧版浏览器中的结尾逗号问题。
// bad - 没有结尾逗号的 git diff const hero = { firstName: 'Florence', - lastName: 'Nightingale' + lastName: 'Nightingale', + inventorOf: ['coxcomb chart', 'modern nursing'] }; // good - 有结尾逗号的 git diff 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 function createHero( firstName, lastName, inventorOf ) { // does nothing } // good function createHero( firstName, lastName, inventorOf, ) { // does nothing } // good (note that a comma must not appear after a "rest" element) function createHero( firstName, lastName, inventorOf, ...heroArgs ) { // does nothing } // bad createHero( firstName, lastName, inventorOf ); // good createHero( firstName, lastName, inventorOf, ); // good (note that a comma must not appear after a "rest" element) createHero( firstName, lastName, inventorOf, ...heroArgs )
Semicolons
-
21.1 Yup. eslint:
semi
Why? 当 JavaScript 遇到没有分号结尾的一行,它会执行自动插入分号
Automatic Semicolon Insertion
这一规则来决定行末是否加分号。如果JavaScript在你的断行里错误的插入了分号,就会出现一些古怪的行为。当新的功能加到JavaScript里后, 这些规则会变得更复杂难懂。显示的结束语句,并通过配置代码检查去捕获没有带分号的地方可以帮助你防止这种错误。// bad (function () { const name = 'Skywalker' return name })() // good (function () { const name = 'Skywalker'; return name; }()); // good, 行首加分号,避免文件被连接到一起时立即执行函数被当做变量来执行。 ;(() => { const name = 'Skywalker'; return name; }());
Read more.
Type Casting & Coercion
- 22.1 在语句开始执行强制类型转换。
-
22.2 Strings: eslint:
no-new-wrappers
// => this.reviewScore = 9; // bad const totalScore = new String(this.reviewScore); // typeof totalScore is "object" not "string" // bad const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf() // bad const totalScore = this.reviewScore.toString(); // 不保证返回string // good const totalScore = String(this.reviewScore);
-
22.3 Numbers: 用
Number
做类型转换,parseInt
转换string常需要带上基数。 eslint:radix
const inputValue = '4'; // bad const val = new Number(inputValue); // bad const val = +inputValue; // bad const val = inputValue >> 0; // bad const val = parseInt(inputValue); // good const val = Number(inputValue); // good const val = parseInt(inputValue, 10);
-
22.6 布尔:
const age = 0; // bad const hasAge = new Boolean(age); // good const hasAge = Boolean(age); // best const hasAge = !!age;
-
23.4 不要用前置或后置下划线。 eslint:
no-underscore-dangle
Why? JavaScript 没有私有属性或私有方法的概念。尽管前置下划线通常的概念上意味着“private”,事实上,这些属性是完全公有的,因此这部分也是你的API的内容。这一概念可能会导致开发者误以为更改这个不会导致崩溃或者不需要测试。 如果你想要什么东西变成“private”,那就不要让它在这里出现。
// bad this.__firstName__ = 'Panda'; this.firstName_ = 'Panda'; this._firstName = 'Panda'; // good this.firstName = 'Panda';
-
23.5 不要保存引用
this
, 用箭头函数或函数绑定——Function#bind.// bad function foo() { const self = this; return function () { console.log(self); }; } // bad function foo() { const that = this; return function () { console.log(that); }; } // good function foo() { return () => { console.log(this); }; }
-
23.6 export default导出模块A,则这个文件名也叫A.*, import 时候的参数也叫A。 大小写完全一致。
// file 1 contents class CheckBox { // ... } export default CheckBox; // file 2 contents export default function fortyTwo() { return 42; } // file 3 contents export default function insideDirectory() {} // in some other file // bad import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export // bad import CheckBox from './check_box'; // PascalCase import/export, snake_case filename import forty_two from './forty_two'; // snake_case import/filename, camelCase export import inside_directory from './inside_directory'; // snake_case import, camelCase export import index from './inside_directory/index'; // requiring the index file explicitly import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly // good import CheckBox from './CheckBox'; // PascalCase export/import/filename import fortyTwo from './fortyTwo'; // camelCase export/import/filename import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index" // ^ supports both insideDirectory.js and insideDirectory/index.js