https://github.com/airbnb/javascript#translation
目錄
- Types
- References
- Objects
- Arrays
- Destructuring
- Strings
- Functions
- Arrow Functions
- Classes & Constructors
- Modules
- Iterators and Generators
- Properties
- Variables
- Hoisting
- Comparison Operators & Equality
- Blocks
- Control Statements
- Comments
- Whitespace
- Commas
Types
<a name="1.1"></a>
<a name="types--primitives"></a>
-
1.1 基本類型: 你可以直接獲取到基本類型的值
string
number
boolean
null
undefined
symbol
const foo = 1; let bar = foo; bar = 9; console.log(foo, bar); // => 1, 9
- Symbols 不能被正確的polyfill诀姚。 所以在不能原生支持symbol類型的環(huán)境[瀏覽器]中,不應該使用 symbol 類型玷禽。
<a name="1.2"></a>
<a name="types--complex"></a>
-
1.2 復雜類型: 復雜類型賦值是獲取到他的引用的值赫段。 相當于傳引用
object
array
function
const foo = [1, 2]; const bar = foo; bar[0] = 9; console.log(foo[0], bar[0]); // => 9, 9
References
<a name="2.1"></a>
<a name="references--prefer-const"></a>
-
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;
<a name="2.2"></a>
<a name="references--disallow-var"></a>
-
2.2 如果你一定要對參數(shù)重新賦值糯笙,那就用
let
,而不是var
. eslint:no-var
Why? 因為
let
是塊級作用域撩银,而var
是函數(shù)級作用域// bad var count = 1; if (true) { count += 1; } // good, use the let. let count = 1; if (true) { count += 1; }
<a name="2.3"></a>
<a name="references--block-scope"></a>
-
2.3 注意:
let
给涕、const
都是塊級作用域// const 和 let 都只存在于它定義的那個塊級作用域 { let a = 1; const b = 1; } console.log(a); // ReferenceError console.log(b); // ReferenceError
Objects
<a name="3.1"></a>
<a name="objects--no-new"></a>
-
3.1 使用字面值創(chuàng)建對象. eslint:
no-new-object
// bad const item = new Object(); // good const item = {};
<a name="3.2"></a>
<a name="es6-computed-properties"></a>
-
3.2 當創(chuàng)建一個帶有動態(tài)屬性名的對象時,用計算后屬性名
Why? 這可以使你將定義的所有屬性放在對象的一個地方.
function getKey(k) { return `a key named ${k}`; } // bad const obj = { id: 5, name: 'San Francisco', }; obj[getKey('enabled')] = true; // good getKey('enabled')是動態(tài)屬性名 const obj = { id: 5, name: 'San Francisco', [getKey('enabled')]: true, };
<a name="3.3"></a>
<a name="es6-object-shorthand"></a>
-
3.3 用對象方法簡寫. eslint:
object-shorthand
// bad const atom = { value: 1, addValue: function (value) { return atom.value + value; }, }; // good const atom = { value: 1, // 對象的方法 addValue(value) { return atom.value + value; }, };
<a name="3.4"></a>
<a name="es6-object-concise"></a>
-
3.4 用屬性值縮寫. eslint:
object-shorthand
Why? 這樣寫的更少且更可讀
const lukeSkywalker = 'Luke Skywalker'; // bad const obj = { lukeSkywalker: lukeSkywalker, }; // good const obj = { lukeSkywalker, };
<a name="3.5"></a>
<a name="objects--grouped-shorthand"></a>
-
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, };
<a name="3.6"></a>
<a name="objects--quoted-props"></a>
-
3.6 只對那些無效的標示使用引號
''
. eslint:quote-props
Why? 通常我們認為這種方式主觀上易讀额获。他優(yōu)化了代碼高亮够庙,并且頁更容易被許多JS引擎壓縮。
// bad const bad = { 'foo': 3, 'bar': 4, 'data-blah': 5, }; // good const good = { foo: 3, bar: 4, 'data-blah': 5, };
<a name="3.7"></a>
<a name="objects--prototype-builtins"></a>
-
3.7 不要直接調用
Object.prototype
上的方法抄邀,如hasOwnProperty
,propertyIsEnumerable
,isPrototypeOf
耘眨。Why? 在一些有問題的對象上, 這些方法可能會被屏蔽掉 - 如:
{ hasOwnProperty: false }
- 或這是一個空對象Object.create(null)
// bad console.log(object.hasOwnProperty(key)); // good console.log(Object.prototype.hasOwnProperty.call(object, key)); // best const has = Object.prototype.hasOwnProperty; // 在模塊作用內做一次緩存 /* or */ import has from 'has'; // https://www.npmjs.com/package/has // ... console.log(has.call(object, key));
<a name="3.8"></a>
<a name="objects--rest-spread"></a>
-
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
<a name="4.1"></a>
<a name="arrays--literals"></a>
-
4.1 用字面量賦值砂心。 eslint:
no-array-constructor
// bad const items = new Array(); // good const items = [];
<a name="4.2"></a>
<a name="arrays--push"></a>
-
4.2 用Array#push 代替直接向數(shù)組中添加一個值。
const someStack = []; // bad someStack[someStack.length] = 'abracadabra'; // good someStack.push('abracadabra');
<a name="4.3"></a>
<a name="es6-array-spreads"></a>
-
4.3 用擴展運算符做數(shù)組淺拷貝楔绞,類似上面的對象淺拷貝
// bad const len = items.length; const itemsCopy = []; let i; for (i = 0; i < len; i += 1) { itemsCopy[i] = items[i]; } // good const itemsCopy = [...items];
<a name="4.4"></a>
<a name="arrays--from-iterable"></a>
-
4.4 用
...
運算符而不是Array.from
來將一個可迭代的對象轉換成數(shù)組结闸。const foo = document.querySelectorAll('.foo'); // good const nodes = Array.from(foo); // best const nodes = [...foo];
<a name="4.5"></a>
<a name="arrays--from-array-like"></a>
-
4.5 用
Array.from
去將一個類數(shù)組對象轉成一個數(shù)組。const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 }; // bad const arr = Array.prototype.slice.call(arrLike); // good const arr = Array.from(arrLike);
<a name="4.6"></a>
<a name="arrays--mapping"></a>
-
4.6 用
Array.from
而不是...
運算符去做map遍歷酒朵。 因為這樣可以避免創(chuàng)建一個臨時數(shù)組桦锄。// bad const baz = [...foo].map(bar); // good const baz = Array.from(foo, bar);
<a name="4.7"></a>
<a name="arrays--callback-return"></a>
-
4.7 在數(shù)組方法的回調函數(shù)中使用 return 語句。 如果函數(shù)體由一條返回一個表達式的語句組成蔫耽, 并且這個表達式沒有副作用结耀, 這個時候可以忽略return,詳見 8.2. eslint:
array-callback-return
// good [1, 2, 3].map((x) => { const y = x + 1; return x * y; }); // good 函數(shù)只有一個語句 [1, 2, 3].map(x => x + 1); // bad - 沒有返回值匙铡, 因為在第一次迭代后acc 就變成undefined了 [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => { const flatten = acc.concat(item); acc[index] = flatten; }); // good [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => { const flatten = acc.concat(item); acc[index] = flatten; return flatten; }); // bad inbox.filter((msg) => { const { subject, author } = msg; if (subject === 'Mockingbird') { return author === 'Harper Lee'; } else { return false; } }); // good inbox.filter((msg) => { const { subject, author } = msg; if (subject === 'Mockingbird') { return author === 'Harper Lee'; } return false; });
<a name="4.8"></a>
<a name="arrays--bracket-newline"></a>
-
4.8 如果一個數(shù)組有很多行图甜,在數(shù)組的
[
后和]
前斷行。 請看下面示例// bad const arr = [ [0, 1], [2, 3], [4, 5], ]; const objectInArray = [{ id: 1, }, { id: 2, }]; const numberInArray = [ 1, 2, ]; // good const arr = [[0, 1], [2, 3], [4, 5]]; const objectInArray = [ { id: 1, }, { id: 2, }, ]; const numberInArray = [ 1, 2, ];
Destructuring
<a name="5.1"></a>
<a name="destructuring--object"></a>
-
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}`; }
<a name="5.2"></a>
<a name="destructuring--array"></a>
-
5.2 用數(shù)組解構.
const arr = [1, 2, 3, 4]; // bad const first = arr[0]; const second = arr[1]; // good const [first, second] = arr;
<a name="5.3"></a>
<a name="destructuring--object-over-array"></a>
-
5.3 多個返回值用對象的解構黑毅,而不是數(shù)據(jù)解構。
Why? 你可以在后期添加新的屬性或者變換變量的順序而不會打破原有的調用
// bad function processInput(input) { // 然后就是見證奇跡的時刻 return [left, right, top, bottom]; } // 調用者需要想一想返回值的順序 const [left, __, top] = processInput(input); // good function processInput(input) { // oops钦讳, 奇跡又發(fā)生了 return { left, right, top, bottom }; } // 調用者只需要選擇他想用的值就好了 const { left, top } = processInput(input);
Strings
<a name="6.1"></a>
<a name="strings--quotes"></a>
-
6.1 對string用單引號
''
矿瘦。 eslint:quotes
// bad const name = "Capt. Janeway"; // bad - 樣例應該包含插入文字或換行 const name = `Capt. Janeway`; // good const name = 'Capt. Janeway';
<a name="6.2"></a>
<a name="strings--line-length"></a>
-
6.2 超過100個字符的字符串不應該用string串聯(lián)成多行。
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.';
<a name="6.3"></a>
<a name="es6-template-literals"></a>
-
6.3 用字符串模板而不是字符串拼接來組織可編程字符串缚去。 eslint:
prefer-template
template-curly-spacing
Why? 模板字符串更具可讀性、語法簡潔琼开、字符串插入?yún)?shù)易结。
// 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}?`; }
<a name="6.4"></a>
<a name="strings--eval"></a>
<a name="6.5"></a>
<a name="strings--escaping"></a>
-
6.5 不要使用不必要的轉義字符搞动。eslint:
no-useless-escape
Why? 反斜線可讀性差,所以他們只在必須使用時才出現(xiàn)哦
// bad const foo = '\'this\' \i\s \"quoted\"'; // good const foo = '\'this\' is "quoted"'; //best const foo = `my name is '${name}'`;
Functions
<a name="7.1"></a>
<a name="functions--declarations"></a>
-
7.1 用命名函數(shù)表達式而不是函數(shù)聲明改橘。eslint:
func-style
函數(shù)表達式: const func = function () {}
函數(shù)聲明: function func() {}
Why? 函數(shù)聲明時作用域被提前了滋尉,這意味著在一個文件里函數(shù)很容易(太容易了)在其定義之前被引用。這樣傷害了代碼可讀性和可維護性飞主。如果你發(fā)現(xiàn)一個函數(shù)又大又復雜狮惜,這個函數(shù)妨礙這個文件其他部分的理解性,這可能就是時候把這個函數(shù)單獨抽成一個模塊了碌识。別忘了給表達式顯示的命名碾篡,不用管這個名字是不是由一個確定的變量推斷出來的,這消除了由匿名函數(shù)在錯誤調用棧產生的所有假設筏餐,這在現(xiàn)代瀏覽器和類似babel編譯器中很常見 (Discussion)
Why? 這一段還不理解這種錯誤發(fā)生的場景开泽,所以只能直譯過來了, 另附原文
Why? Function declarations are hoisted, which means that it’s easy - too easy - to reference the function before it is defined in the file. This harms readability and maintainability. If you find that a function’s definition is large or complex enough that it is interfering with understanding the rest of the file, then perhaps it’s time to extract it to its own module! Don’t forget to explicitly name the expression, regardless of whether or not the name is inferred from the containing variable (which is often the case in modern browsers or when using compilers such as Babel). This eliminates any assumptions made about the Error’s call stack. (Discussion)// bad function foo() { // ... } // bad const foo = function () { // ... }; // good // lexical name distinguished from the variable-referenced invocation(s) // 函數(shù)表達式名和聲明的函數(shù)名是不一樣的 const short = function longUniqueMoreDescriptiveLexicalFoo() { // ... };
<a name="7.2"></a>
<a name="functions--iife"></a>
-
7.2 把立即執(zhí)行函數(shù)包裹在圓括號里魁瞪。 eslint:
wrap-iife
Why? immediately invoked function expression = IIFE
Why? 一個立即調用的函數(shù)表達式是一個單元 - 把它和他的調用者(圓括號)包裹起來穆律,在括號中可以清晰的地表達這些惠呼。
Why? 注意:在模塊化世界里,你幾乎用不著 IIFE// immediately-invoked function expression (IIFE) (function () { console.log('Welcome to the Internet. Please follow me.'); }());
<a name="7.3"></a>
<a name="functions--in-blocks"></a>
-
7.3 不要在非函數(shù)塊(if峦耘、while等等)內聲明函數(shù)剔蹋。把這個函數(shù)分配給一個變量。瀏覽器會允許你這樣做辅髓,但瀏覽器解析方式不同泣崩,這是一個壞消息÷蹇冢【詳見
no-loop-func
】 eslint:no-loop-func
<a name="7.4"></a>
<a name="functions--note-on-blocks"></a>
-
7.4 Note: 在ECMA-262中 [塊
block
] 的定義是: 一系列的語句矫付; 但是函數(shù)聲明不是一個語句。 函數(shù)表達式是一個語句第焰。// bad if (currentUser) { function test() { console.log('Nope.'); } } // good let test; if (currentUser) { test = () => { console.log('Yup.'); }; }
<a name="7.5"></a>
<a name="functions--arguments-shadow"></a>
-
7.5 不要用
arguments
命名參數(shù)买优。他的優(yōu)先級高于每個函數(shù)作用域自帶的arguments
對象, 這會導致函數(shù)自帶的arguments
值被覆蓋// bad function foo(name, options, arguments) { // ... } // good function foo(name, options, args) { // ... }
<a name="7.6"></a>
<a name="es6-rest"></a>
-
7.6 不要使用
arguments
樟遣,用rest語法...
代替而叼。 eslint:prefer-rest-params
Why?
...
明確你想用那個參數(shù)。而且rest參數(shù)是真數(shù)組豹悬,而不是類似數(shù)組的arguments
// bad function concatenateAll() { const args = Array.prototype.slice.call(arguments); return args.join(''); } // good function concatenateAll(...args) { return args.join(''); }
<a name="7.7"></a>
<a name="es6-default-parameters"></a>
-
7.7 用默認參數(shù)語法而不是在函數(shù)里對參數(shù)重新賦值葵陵。
// 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 = {}) { // ... }
<a name="7.8"></a>
<a name="functions--default-side-effects"></a>
-
7.8 默認參數(shù)避免副作用
Why? 他會令人迷惑不解脱篙, 比如下面這個, a到底等于幾伤柄, 這個需要想一下绊困。
var b = 1; // bad function count(a = b++) { console.log(a); } count(); // 1 count(); // 2 count(3); // 3 count(); // 3
<a name="7.9"></a>
<a name="functions--defaults-last"></a>
-
7.9 把默認參數(shù)賦值放在最后
// bad function handleThings(opts = {}, name) { // ... } // good function handleThings(name, opts = {}) { // ... }
<a name="7.10"></a>
<a name="functions--constructor"></a>
-
7.10 不要用函數(shù)構造器創(chuàng)建函數(shù)。 eslint:
no-new-func
Why? 以這種方式創(chuàng)建函數(shù)將類似于字符串 eval()适刀,這會打開漏洞秤朗。
// bad var add = new Function('a', 'b', 'return a + b'); // still bad var subtract = Function('a', 'b', 'return a - b');
<a name="7.11"></a>
<a name="functions--signature-spacing"></a>
-
7.11 函數(shù)簽名部分要有空格。eslint:
space-before-function-paren
space-before-blocks
Why? 統(tǒng)一性好笔喉,而且在你添加/刪除一個名字的時候不需要添加/刪除空格
// bad const f = function(){}; const g = function (){}; const h = function() {}; // good const x = function () {}; const y = function a() {};
<a name="7.12"></a>
<a name="functions--mutate-params"></a>
-
7.12 不要改參數(shù). eslint:
no-param-reassign
Why? 操作參數(shù)對象對原始調用者會導致意想不到的副作用取视。 就是不要改參數(shù)的數(shù)據(jù)結構,保留參數(shù)原始值和數(shù)據(jù)結構常挚。
// bad function f1(obj) { obj.key = 1; }; // good function f2(obj) { const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1; };
<a name="7.13"></a>
<a name="functions--reassign-params"></a>
-
7.13 不要對參數(shù)重新賦值作谭。 eslint:
no-param-reassign
Why? 參數(shù)重新賦值會導致意外行為,尤其是對
arguments
奄毡。這也會導致優(yōu)化問題折欠,特別是在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) { // ... }
<a name="7.14"></a>
<a name="functions--spread-vs-apply"></a>
-
7.14 用
spread
操作符...
去調用多變的函數(shù)更好。 eslint:prefer-spread
Why? 這樣更清晰,你不必提供上下文锐秦,而且你不能輕易地用
apply
來組成new
// bad const x = [1, 2, 3, 4, 5]; console.log.apply(console, x); // good const x = [1, 2, 3, 4, 5]; console.log(...x); // bad new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5])); // good new Date(...[2016, 8, 5]);
<a name="7.15"></a>
<a name="functions--signature-invocation-indentation"></a>
-
7.15 調用或者書寫一個包含多個參數(shù)的函數(shù)應該像這個指南里的其他多行代碼寫法一樣: 每行值包含一個參數(shù)咪奖,每行逗號結尾。
// bad function foo(bar, baz, quux) { // ... } // good 縮進不要太過分 function foo( bar, baz, quux, ) { // ... } // bad console.log(foo, bar, baz); // good console.log( foo, bar, baz, );
Arrow Functions
<a name="8.1"></a>
<a name="arrows--use-them"></a>
-
8.1 當你一定要用函數(shù)表達式(在回調函數(shù)里)的時候就用箭頭表達式吧农猬。 eslint:
prefer-arrow-callback
,arrow-spacing
Why? 他創(chuàng)建了一個
this
的當前執(zhí)行上下文的函數(shù)的版本赡艰,這通常就是你想要的售淡;而且箭頭函數(shù)是更簡潔的語法Why? 什么時候不用箭頭函數(shù): 如果你有一個相當復雜的函數(shù)斤葱,你可能會把這個邏輯移出到他自己的函數(shù)聲明里。
// bad [1, 2, 3].map(function (x) { const y = x + 1; return x * y; }); // good [1, 2, 3].map((x) => { const y = x + 1; return x * y; });
<a name="8.2"></a>
<a name="arrows--implicit-return"></a>
-
8.2 如果函數(shù)體由一個沒有副作用的表達式語句組成揖闸,刪除大括號和return揍堕。否則,繼續(xù)用大括號和
return
語句汤纸。 eslint:arrow-parens
,arrow-body-style
Why? 語法糖衩茸,當多個函數(shù)鏈在一起的時候好讀
// bad [1, 2, 3].map(number => { const nextNumber = number + 1; `A string containing the ${nextNumber}.`; }); // good [1, 2, 3].map(number => `A string containing the ${number}.`); // good [1, 2, 3].map((number) => { const nextNumber = number + 1; return `A string containing the ${nextNumber}.`; }); // good [1, 2, 3].map((number, index) => ({ [index]: number })); // 表達式有副作用就不要用隱式return function foo(callback) { const val = callback(); if (val === true) { // Do something if callback returns true } } let bool = false; // bad // 這種情況會return bool = true, 不好 foo(() => bool = true); // good foo(() => { bool = true; });
<a name="8.3"></a>
<a name="arrows--paren-wrap"></a>
-
8.3 萬一表達式涉及多行,把他包裹在圓括號里更可讀贮泞。
Why? 這樣清晰的顯示函數(shù)的開始和結束
// bad ['get', 'post', 'put'].map(httpMethod => Object.prototype.hasOwnProperty.call( httpMagicObjectWithAVeryLongName, httpMethod ) ); // good ['get', 'post', 'put'].map(httpMethod => ( Object.prototype.hasOwnProperty.call( httpMagicObjectWithAVeryLongName, httpMethod ) ));
<a name="8.4"></a>
<a name="arrows--one-arg-parens"></a>
-
8.4 如果你的函數(shù)只有一個參數(shù)并且函數(shù)體沒有大括號楞慈,就刪除圓括號。否則啃擦,參數(shù)總是放在圓括號里囊蓝。 注意: 一直用圓括號也是沒問題,只需要配置 “always” option for eslint. eslint:
arrow-parens
Why? 這樣少一些混亂令蛉, 其實沒啥語法上的講究聚霜,就保持一個風格。
// bad [1, 2, 3].map((x) => x * x); // good [1, 2, 3].map(x => x * x); // good [1, 2, 3].map(number => ( `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!` )); // bad [1, 2, 3].map(x => { const y = x + 1; return x * y; }); // good [1, 2, 3].map((x) => { const y = x + 1; return x * y; });
<a name="8.5"></a>
<a name="arrows--confusing"></a>
-
8.5 避免箭頭函數(shù)(
=>
)和比較操作符(<=, >=
)混淆. eslint:no-confusing-arrow
// bad const itemHeight = (item) => item.height <= 256 ? item.largeSize : item.smallSize; // bad const itemHeight = (item) => item.height >= 256 ? item.largeSize : item.smallSize; // good const itemHeight = (item) => (item.height <= 256 ? item.largeSize : item.smallSize); // good const itemHeight = (item) => { const { height, largeSize, smallSize } = item; return height <= 256 ? largeSize : smallSize; };
<a name="8.6"></a>
<a name="whitespace--implicit-arrow-linebreak"></a>
-
8.6 在隱式return中強制約束函數(shù)體的位置珠叔, 就寫在箭頭后面蝎宇。 eslint:
implicit-arrow-linebreak
// bad (foo) => bar; (foo) => (bar); // good (foo) => bar; (foo) => (bar); (foo) => ( bar )
Classes & Constructors
<a name="9.1"></a>
<a name="constructors--use-class"></a>
-
9.1 常用
class
,避免直接操作prototype
Why?
class
語法更簡潔更易理解// bad function Queue(contents = []) { this.queue = [...contents]; } Queue.prototype.pop = function () { const value = this.queue[0]; this.queue.splice(0, 1); return value; }; // good class Queue { constructor(contents = []) { this.queue = [...contents]; } pop() { const value = this.queue[0]; this.queue.splice(0, 1); return value; } }
<a name="9.2"></a>
<a name="constructors--extends"></a>
-
9.2 用
extends
實現(xiàn)繼承Why? 它是一種內置的方法來繼承原型功能而不打破
instanceof
// bad const inherits = require('inherits'); function PeekableQueue(contents) { Queue.apply(this, contents); } inherits(PeekableQueue, Queue); PeekableQueue.prototype.peek = function () { return this.queue[0]; } // good class PeekableQueue extends Queue { peek() { return this.queue[0]; } }
<a name="9.3"></a>
<a name="constructors--chaining"></a>
-
9.3 方法可以返回
this
來實現(xiàn)方法鏈// bad Jedi.prototype.jump = function () { this.jumping = true; return true; }; Jedi.prototype.setHeight = function (height) { this.height = height; }; const luke = new Jedi(); luke.jump(); // => true luke.setHeight(20); // => undefined // good class Jedi { jump() { this.jumping = true; return this; } setHeight(height) { this.height = height; return this; } } const luke = new Jedi(); luke.jump() .setHeight(20);
<a name="9.4"></a>
<a name="constructors--tostring"></a>
-
9.4 寫一個定制的toString()方法是可以的祷安,只要保證它是可以正常工作且沒有副作用的
class Jedi { constructor(options = {}) { this.name = options.name || 'no name'; } getName() { return this.name; } toString() { return `Jedi - ${this.getName()}`; } }
<a name="9.5"></a>
<a name="constructors--no-useless"></a>
-
9.5 如果沒有具體說明姥芥,類有默認的構造方法。一個空的構造函數(shù)或只是代表父類的構造函數(shù)是不需要寫的汇鞭。 eslint:
no-useless-constructor
// bad class Jedi { constructor() {} getName() { return this.name; } } // bad class Rey extends Jedi { // 這種構造函數(shù)是不需要寫的 constructor(...args) { super(...args); } } // good class Rey extends Jedi { constructor(...args) { super(...args); this.name = 'Rey'; } }
<a name="9.6"></a>
<a name="classes--no-duplicate-members"></a>
-
9.6 避免重復類成員凉唐。 eslint:
no-dupe-class-members
Why? 重復類成員會默默的執(zhí)行最后一個 —— 重復本身也是一個bug
// bad class Foo { bar() { return 1; } bar() { return 2; } } // good class Foo { bar() { return 1; } } // good class Foo { bar() { return 2; } }
<a name="classes--methods-use-this"></a>
-
9.7 除非外部庫或框架需要使用特定的非靜態(tài)方法,否則類方法應該使用
this
或被做成靜態(tài)方法虱咧。
作為一個實例方法應該表明它根據(jù)接收者的屬性有不同的行為熊榛。eslint:class-methods-use-this
// bad class Foo { bar() { console.log('bar'); } } // good - this 被使用了 class Foo { bar() { console.log(this.bar); } } // good - constructor 不一定要使用this class Foo { constructor() { // ... } } // good - 靜態(tài)方法不需要使用 this class Foo { static bar() { console.log('bar'); } }
Modules
<a name="10.1"></a>
<a name="modules--use-them"></a>
-
10.1 用(
import
/export
) 模塊而不是無標準的模塊系統(tǒng)。你可以隨時轉到你喜歡的模塊系統(tǒng)腕巡。Why? 模塊化是未來玄坦,讓我們現(xiàn)在就開啟未來吧。
// bad const AirbnbStyleGuide = require('./AirbnbStyleGuide'); module.exports = AirbnbStyleGuide.es6; // ok import AirbnbStyleGuide from './AirbnbStyleGuide'; export default AirbnbStyleGuide.es6; // best import { es6 } from './AirbnbStyleGuide'; export default es6;
<a name="10.2"></a>
<a name="modules--no-wildcard"></a>
-
10.2 不要用import通配符, 就是
*
這種方式Why? 這確保你有單個默認的導出
// bad import * as AirbnbStyleGuide from './AirbnbStyleGuide'; // good import AirbnbStyleGuide from './AirbnbStyleGuide';
<a name="10.3"></a>
<a name="modules--no-export-from-import"></a>
-
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;
<a name="10.4"></a>
<a name="modules--no-duplicate-imports"></a>
-
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';
<a name="10.5"></a>
<a name="modules--no-mutable-exports"></a>
-
10.5 不要導出可變的東西
eslint:import/no-mutable-exports
Why? 變化通常都是需要避免择懂,特別是當你要輸出可變的綁定喻喳。雖然在某些場景下可能需要這種技術,但總的來說應該導出常量困曙。
// bad let foo = 3; export { foo } // good const foo = 3; export { foo }
<a name="10.6"></a>
<a name="modules--prefer-default-export"></a>
-
10.6 在一個單一導出模塊里表伦,用
export default
更好。
eslint:import/prefer-default-export
Why? 鼓勵使用更多文件慷丽,每個文件只做一件事情并導出蹦哼,這樣可讀性和可維護性更好。
// bad export function foo() {} // good export default function foo() {}
<a name="10.7"></a>
<a name="modules--imports-first"></a>
-
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();
<a name="10.8"></a>
<a name="modules--multiline-imports-over-newlines"></a>
-
10.8 多行import應該縮進,就像多行數(shù)組和對象字面量
Why? 花括號與樣式指南中每個其他花括號塊遵循相同的縮進規(guī)則锄俄,逗號也是局劲。
// bad import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path'; // good import { longNameA, longNameB, longNameC, longNameD, longNameE, } from 'path';
<a name="10.9"></a>
<a name="modules--no-webpack-loader-syntax"></a>
-
10.9 在import語句里不允許Webpack loader語法
eslint:import/no-webpack-loader-syntax
Why? 一旦用Webpack語法在import里會把代碼耦合到模塊綁定器。最好是在
webpack.config.js
里寫webpack loader語法// bad import fooSass from 'css!sass!foo.scss'; import barCss from 'style!css!bar.css'; // good import fooSass from 'foo.scss'; import barCss from 'bar.css';
Iterators and Generators
<a name="11.1"></a>
<a name="iterators--nope"></a>
-
11.1 不要用遍歷器奶赠。用JavaScript高級函數(shù)代替
for-in
鱼填、for-of
。 eslint:no-iterator
no-restricted-syntax
Why? 這強調了我們不可變的規(guī)則车柠。 處理返回值的純函數(shù)比副作用更容易剔氏。
Why? 用數(shù)組的這些迭代方法:
map()
/every()
/filter()
/find()
/findIndex()
/reduce()
/some()
/ ... , 用對象的這些方法Object.keys()
/Object.values()
/Object.entries()
去產生一個數(shù)組, 這樣你就能去遍歷對象了竹祷。const numbers = [1, 2, 3, 4, 5]; // bad let sum = 0; for (let num of numbers) { sum += num; } sum === 15; // good let sum = 0; numbers.forEach(num => sum += num); sum === 15; // best (use the functional force) const sum = numbers.reduce((total, num) => total + num, 0); sum === 15; // bad const increasedByOne = []; for (let i = 0; i < numbers.length; i++) { increasedByOne.push(numbers[i] + 1); } // good const increasedByOne = []; numbers.forEach(num => increasedByOne.push(num + 1)); // best (keeping it functional) const increasedByOne = numbers.map(num => num + 1);
<a name="11.2"></a>
<a name="generators--nope"></a>
-
11.2 現(xiàn)在不要用generator
Why? 它在es5上支持的不好
<a name="11.3"></a>
<a name="generators--spacing"></a>
-
11.3 如果你一定要用谈跛,或者你忽略我們的建議, 請確保它們的函數(shù)簽名空格是得當?shù)摹?eslint:
generator-star-spacing
Why?
function
和*
是同一概念關鍵字 -*
不是function
的修飾符,function*
是一個和function
不一樣的獨特結構// bad function * foo() { // ... } // bad const bar = function * () { // ... } // bad const baz = function *() { // ... } // bad const quux = function*() { // ... } // bad function*foo() { // ... } // bad function *foo() { // ... } // very bad function * foo() { // ... } // very bad const wat = function * () { // ... } // good function* foo() { // ... } // good const foo = function* () { // ... }
Properties
<a name="12.1"></a>
<a name="properties--dot"></a>
-
12.1 訪問屬性時使用點符號. eslint:
dot-notation
const luke = { jedi: true, age: 28, }; // bad const isJedi = luke['jedi']; // good const isJedi = luke.jedi;
<a name="12.2"></a>
<a name="properties--bracket"></a>
-
12.2 當獲取的屬性是變量時用方括號
[]
取const luke = { jedi: true, age: 28, }; function getProp(prop) { return luke[prop]; } const isJedi = getProp('jedi');
<a name="12.3"></a>
<a name="es2016-properties--exponentiation-operator"></a>
-
12.3 做冪運算時用冪操作符
**
塑陵。 eslint:no-restricted-properties
.// bad const binary = Math.pow(2, 10); // good const binary = 2 ** 10;
Variables
<a name="13.1"></a>
<a name="variables--const"></a>
-
13.1 用
const
或let
聲明變量感憾。不這樣做會導致全局變量。 我們想要避免污染全局命名空間令花。首長這樣警告我們阻桅。 eslint:no-undef
prefer-const
// bad superPower = new SuperPower(); // good const superPower = new SuperPower();
<a name="13.2"></a>
<a name="variables--one-const"></a>
-
13.2 每個變量都用一個
const
或let
。 eslint:one-var
Why? 這種方式很容易去聲明新的變量兼都,你不用去考慮把
;
調換成,
嫂沉,或者引入一個只有標點的不同的變化。這種做法也可以是你在調試的時候單步每個聲明語句扮碧,而不是一下跳過所有聲明趟章。// bad const items = getItems(), goSportsTeam = true, dragonball = 'z'; // bad // (compare to above, and try to spot the mistake) const items = getItems(), goSportsTeam = true; dragonball = 'z'; // good const items = getItems(); const goSportsTeam = true; const dragonball = 'z';
<a name="13.3"></a>
<a name="variables--const-let-group"></a>
-
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;
<a name="13.4"></a>
<a name="variables--define-where-used"></a>
-
13.4 在你需要的地方聲明變量宏侍,但是要放在合理的位置
Why?
let
和const
都是塊級作用域而不是函數(shù)級作用域// bad - unnecessary function call function checkName(hasName) { const name = getName(); if (hasName === 'test') { return false; } if (name === 'test') { this.setName(''); return false; } return name; } // good function checkName(hasName) { if (hasName === 'test') { return false; } // 在需要的時候分配 const name = getName(); if (name === 'test') { this.setName(''); return false; } return name; }
<a name="13.5"></a>
<a name="variables--no-chain-assignment"></a>
-
13.5 不要使用鏈接變量分配。 eslint:
no-multi-assign
Why? 鏈接變量分配創(chuàng)建隱式全局變量蜀漆。
// 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` 也是如此
<a name="13.6"></a>
<a name="variables--unary-increment-decrement"></a>
-
13.6 不要使用一元自增自減運算符(
++
谅河,--
). eslintno-plusplus
Why? 根據(jù)eslint文檔,一元增量和減量語句受到自動分號插入的影響确丢,并且可能會導致應用程序中的值遞增或遞減的無聲錯誤绷耍。 使用
num + = 1
而不是num ++
或num ++
語句來表達你的值也是更有表現(xiàn)力的。 禁止一元增量和減量語句還會阻止您無意地預增/預減值蠕嫁,這也會導致程序出現(xiàn)意外行為锨天。// bad const 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 const 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;
<a name="13.7"></a>
<a name="variables--linebreak"></a>
-
13.7 在賦值的時候避免在
=
前/后換行。 如果你的賦值語句超出max-len
剃毒, 那就用小括號把這個值包起來再換行。 eslintoperator-linebreak
.Why? 在
=
附近換行容易混淆這個賦值語句搂赋。// bad const foo = superLongLongLongLongLongLongLongLongFunctionName(); // bad const foo = 'superLongLongLongLongLongLongLongLongString'; // good const foo = ( superLongLongLongLongLongLongLongLongFunctionName() ); // good const foo = 'superLongLongLongLongLongLongLongLongString';
<a name="13.8"></a>
<a name="variables--no-unused-vars"></a>
-
13.8 不允許有未使用的變量赘阀。 eslint:
no-unused-vars
Why? 一個聲明了但未使用的變量更像是由于重構未完成產生的錯誤。這種在代碼中出現(xiàn)的變量會使閱讀者迷惑脑奠。
// bad var some_unused_var = 42; // 寫了沒用 var y = 10; y = 5; // 變量改了自己的值基公,也沒有用這個變量 var z = 0; z = z + 1; // 參數(shù)定義了但未使用 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' 現(xiàn)在就是一個沒有 'type' 屬性的 'data' 對象
Hoisting
<a name="14.1"></a>
<a name="hoisting--about"></a>
-
14.1
var
聲明會被提前到他的作用域的最前面轰豆,它分配的值還沒有提前。const
和let
被賦予了新的調用概念時效區(qū) —— Temporal Dead Zones (TDZ)齿诞。 重要的是要知道為什么 typeof不再安全.// 我們知道這個不會工作酸休,假設沒有定義全局的notDefined function example() { console.log(notDefined); // => throws a ReferenceError } // 在你引用的地方之后聲明一個變量,他會正常輸出是因為變量作用域上升祷杈。 // 注意: declaredButNotAssigned的值沒有上升 function example() { console.log(declaredButNotAssigned); // => undefined var declaredButNotAssigned = true; } // 解釋器把變量聲明提升到作用域最前面斑司, // 可以重寫成如下例子, 二者意義相同 function example() { let declaredButNotAssigned; console.log(declaredButNotAssigned); // => undefined declaredButNotAssigned = true; } // 用 const但汞, let就不一樣了 function example() { console.log(declaredButNotAssigned); // => throws a ReferenceError console.log(typeof declaredButNotAssigned); // => throws a ReferenceError const declaredButNotAssigned = true; }
<a name="14.2"></a>
<a name="hoisting--anon-expressions"></a>
-
14.2 匿名函數(shù)表達式和
var
情況相同function example() { console.log(anonymous); // => undefined anonymous(); // => TypeError anonymous is not a function var anonymous = function () { console.log('anonymous function expression'); }; }
<a name="14.3"></a>
<a name="hoisting--named-expresions"></a>
-
14.3 已命名函數(shù)表達式提升他的變量名宿刮,不是函數(shù)名或函數(shù)體
function example() { console.log(named); // => undefined named(); // => TypeError named is not a function superPower(); // => ReferenceError superPower is not defined var named = function superPower() { console.log('Flying'); }; } // 函數(shù)名和變量名一樣是也如此 function example() { console.log(named); // => undefined named(); // => TypeError named is not a function var named = function named() { console.log('named'); }; }
<a name="14.4"></a>
<a name="hoisting--declarations"></a>
-
14.4 函數(shù)聲明則提升了函數(shù)名和函數(shù)體
function example() { superPower(); // => Flying function superPower() { console.log('Flying'); } }
Comparison Operators & Equality
<a name="15.1"></a>
<a name="comparison--eqeqeq"></a>
<a name="15.2"></a>
<a name="comparison--if"></a>
-
15.2 條件語句如'if'語句使用強制`ToBoolean'抽象方法來評估它們的表達式,并且始終遵循以下簡單規(guī)則:
- Objects 計算成 true
- Undefined 計算成 false
- Null 計算成 false
- Booleans 計算成 the value of the boolean
-
Numbers
- +0, -0, or NaN 計算成 false
- 其他 true
-
Strings
-
''
計算成 false - 其他 true
-
if ([0] && []) { // true // 數(shù)組(即使是空數(shù)組)是對象私蕾,對象會計算成true }
<a name="15.3"></a>
<a name="comparison--shortcuts"></a>
-
15.3 布爾值用縮寫僵缺,而字符串和數(shù)字要明確比較對象
// bad if (isValid === true) { // ... } // good if (isValid) { // ... } // bad if (name) { // ... } // good if (name !== '') { // ... } // bad if (collection.length) { // ... } // good if (collection.length > 0) { // ... }
<a name="15.4"></a>
<a name="comparison--moreinfo"></a>
- 15.4 更多信息請見Angus Croll的真理、平等和JavaScript —— Truth Equality and JavaScript
<a name="15.5"></a>
<a name="comparison--switch-blocks"></a>
-
15.5 在
case
和default
分句里用大括號創(chuàng)建一塊包含語法聲明的區(qū)域(e.g.let
,const
,function
, andclass
). eslint rules:no-case-declarations
.Why? 語法聲明在整個
switch
的代碼塊里都可見踩叭,但是只有當其被分配后才會初始化磕潮,他的初始化時當這個case
被執(zhí)行時才產生。 當多個case
分句試圖定義同一個事情時就出問題了// bad switch (foo) { case 1: let x = 1; break; case 2: const y = 2; break; case 3: function f() { // ... } break; default: class C {} } // good switch (foo) { case 1: { let x = 1; break; } case 2: { const y = 2; break; } case 3: { function f() { // ... } break; } case 4: bar(); break; default: { class C {} } }
<a name="15.6"></a>
<a name="comparison--nested-ternaries"></a>
-
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;
<a name="15.7"></a>
<a name="comparison--unneeded-ternary"></a>
-
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;
<a name="15.8"></a>
<a name="comparison--no-mixed-operators"></a>
-
15.8 用圓括號來混合這些操作符亡容。 只有當標準的算術運算符(
+
,-
,*
, &/
), 并且它們的優(yōu)先級顯而易見時冤今,可以不用圓括號括起來闺兢。 eslint:no-mixed-operators
Why? 這提高了可讀性,并且明確了開發(fā)者的意圖
// 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
<a name="16.1"></a>
<a name="blocks--braces"></a>
-
16.1 用大括號包裹多行代碼塊戏罢。 eslint:
nonblock-statement-body-position
// bad if (test) return false; // good if (test) return false; // good if (test) { return false; } // bad function foo() { return false; } // good function bar() { return false; }
<a name="16.2"></a>
<a name="blocks--cuddled-elses"></a>
-
16.2
if
表達式的else
和if
的關閉大括號在一行屋谭。 eslint:brace-style
// bad if (test) { thing1(); thing2(); } else { thing3(); } // good if (test) { thing1(); thing2(); } else { thing3(); }
<a name="16.3"></a>
<a name="blocks--no-else-return"></a>
-
16.3 如果
if
語句中總是需要用return
返回, 那后續(xù)的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
<a name="17.1"></a>
<a name="control-statements"></a>
-
17.1 當你的控制語句(
if
,while
等)太長或者超過最大長度限制的時候我擂, 把每一個(組)判斷條件放在單獨一行里。 邏輯操作符放在行首缓艳。Why? 把邏輯操作符放在行首是讓操作符的對齊方式和鏈式函數(shù)保持一致校摩。這提高了可讀性,也讓復雜邏輯更容易看清楚阶淘。
// 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(); }
<a name="17.2"></a>
<a name="control-statements--value-selection"></a>
-
17.2 不要用選擇操作符代替控制語句衙吩。
// bad !isRunning && startRunning(); // good if (!isRunning) { startRunning(); }
Comments
<a name="18.1"></a>
<a name="comments--multiline"></a>
-
18.1 多行注釋用
/** ... */
// bad // make() returns a new element // based on the passed in tag name // // @param {String} tag // @return {Element} element function make(tag) { // ... return element; } // good /** * make() returns a new element * based on the passed-in tag name */ function make(tag) { // ... return element; }
<a name="18.2"></a>
<a name="comments--singleline"></a>
-
18.2 單行注釋用
//
,將單行注釋放在被注釋區(qū)域上面溪窒。如果注釋不是在第一行坤塞,那么注釋前面就空一行// bad const active = true; // is current tab // good // is current tab const active = true; // bad function getType() { console.log('fetching type...'); // set the default type to 'no type' const type = this._type || 'no type'; return type; } // good function getType() { console.log('fetching type...'); // set the default type to 'no type' const type = this._type || 'no type'; return type; } // also good function getType() { // set the default type to 'no type' const type = this._type || 'no type'; return type; }
<a name="18.3"></a>
<a name="comments--spaces"></a>
-
18.3 所有注釋開頭空一個,方便閱讀澈蚌。 eslint:
spaced-comment
// bad //is current tab const active = true; // good // is current tab const active = true; // bad /** *make() returns a new element *based on the passed-in tag name */ function make(tag) { // ... return element; } // good /** * make() returns a new element * based on the passed-in tag name */ function make(tag) { // ... return element; }
<a name="18.4"></a>
<a name="comments--actionitems"></a>
-
18.4 在你的注釋前使用
FIXME'或
TODO'前綴摹芙, 這有助于其他開發(fā)人員快速理解你指出的需要重新訪問的問題, 或者您建議需要實現(xiàn)的問題的解決方案瘫辩。 這些不同于常規(guī)注釋坛悉,因為它們是可操作的。 動作是FIXME: - 需要計算出來
或TODO: - 需要實現(xiàn)
裸影。
<a name="18.5"></a>
<a name="comments--fixme"></a>
-
18.5 用
// FIXME:
給問題做注釋class Calculator extends Abacus { constructor() { super(); // FIXME: shouldn't use a global here total = 0; } }
<a name="18.6"></a>
<a name="comments--todo"></a>
-
18.6 用
// TODO:
去注釋問題的解決方案class Calculator extends Abacus { constructor() { super(); // TODO: total should be configurable by an options param this.total = 0; } }
Whitespace
<a name="19.1"></a>
<a name="whitespace--spaces"></a>
-
// bad function foo() { ????const name; } // bad function bar() { ?const name; } // good function baz() { ??const name; }
<a name="19.2"></a>
<a name="whitespace--before-blocks"></a>
-
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', });
<a name="19.3"></a>
<a name="whitespace--around-keywords"></a>
-
19.3 在控制語句(
if
,while
等)的圓括號前空一格卷扮。在函數(shù)調用和定義時,參數(shù)列表和函數(shù)名之間不空格摩幔。 eslint:keyword-spacing
// bad if(isJedi) { fight (); } // good if (isJedi) { fight(); } // bad function fight () { console.log ('Swooosh!'); } // good function fight() { console.log('Swooosh!'); }
<a name="19.4"></a>
<a name="whitespace--infix-ops"></a>
-
19.4 用空格來隔開運算符鞭铆。 eslint:
space-infix-ops
// bad const x=y+5; // good const x = y + 5;
<a name="19.5"></a>
<a name="whitespace--newline-at-end"></a>
-
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;?
<a name="19.6"></a>
<a name="whitespace--chains"></a>
-
19.6 當出現(xiàn)長的方法鏈(>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);
<a name="19.7"></a>
<a name="whitespace--after-blocks"></a>
-
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;
<a name="19.8"></a>
<a name="whitespace--padded-blocks"></a>
-
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); }
<a name="whitespace--no-multiple-blanks"></a>
-
19.9不要在代碼之間使用多個空白行填充箱季。 eslint:
no-multiple-empty-lines
// bad class Person { constructor(fullName, email, birthday) { this.fullName = fullName; this.email = email; this.setAge(birthday); } setAge(birthday) { const today = new Date(); const age = this.getAge(today, birthday); this.age = age; } getAge(today, birthday) { // .. } } // good class Person { constructor(fullName, email, birthday) { this.fullName = fullName; this.email = email; this.setAge(birthday); } setAge(birthday) { const today = new Date(); const age = getAge(today, birthday); this.age = age; } getAge(today, birthday) { // .. } }
<a name="19.10"></a>
<a name="whitespace--in-parens"></a>
-
19.10 圓括號里不要加空格锈津。 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); }
<a name="19.11"></a>
<a name="whitespace--in-brackets"></a>
-
19.11 方括號里不要加空格隆箩“齐看示例。 eslint:
array-bracket-spacing
// bad const foo = [ 1, 2, 3 ]; console.log(foo[ 0 ]); // good逞力, 逗號分隔符還是要空格的 const foo = [1, 2, 3]; console.log(foo[0]);
<a name="19.12"></a>
<a name="whitespace--in-braces"></a>
-
19.12 花括號里加空格糠爬。 eslint:
object-curly-spacing
// bad const foo = {clark: 'kent'}; // good const foo = { clark: 'kent' };
<a name="19.13"></a>
<a name="whitespace--max-len"></a>
19.13 避免一行代碼超過100個字符(包含空格)执隧。
-
注意: 對于上面——strings--line-length,長字符串不受此規(guī)則限制峦嗤,不應分解。 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.'));
<a name="19.14"></a>
<a name="whitespace--block-spacing"></a>
-
19.14 作為語句的花括號內也要加空格 ——
{
后和}
前都需要空格耙替。 eslint:block-spacing
// bad function foo() {return true;} if (foo) { bar = 0;} // good function foo() { return true; } if (foo) { bar = 0; }
<a name="19.15"></a>
<a name="whitespace--comma-spacing"></a>
-
19.15
,
前不要空格俗扇,,
后需要空格铜幽。 eslint:comma-spacing
// bad var foo = 1,bar = 2; var arr = [1 , 2]; // good var foo = 1, bar = 2; var arr = [1, 2];
<a name="19.16"></a>
<a name="whitespace--computed-property-spacing"></a>
-
19.16 計算屬性內要空格除抛。參考上述花括號和中括號的規(guī)則母截。 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]]
<a name="19.17"></a>
<a name="whitespace--func-call-spacing"></a>
-
19.17 調用函數(shù)時清寇,函數(shù)名和小括號之間不要空格华烟。 eslint:
func-call-spacing
// bad func (); func (); // good func();
<a name="19.18"></a>
<a name="whitespace--key-spacing"></a>
-
19.18 在對象的字面量屬性中,
key
value
之間要有空格负饲。 eslint:key-spacing
// bad var obj = { "foo" : 42 }; var obj2 = { "foo":42 }; // good var obj = { "foo": 42 };
<a name="19.19"></a>
<a name="whitespace--no-trailing-spaces"></a>
-
19.19 行末不要空格返十。 eslint:
no-trailing-spaces
<a name="19.20"></a>
<a name="whitespace--no-multiple-empty-lines"></a>
-
19.20 避免出現(xiàn)多個空行吧慢。 在文件末尾只允許空一行赏表。 eslint:
no-multiple-empty-lines
// bad var x = 1; var y = 2; // good var x = 1; var y = 2;
Commas
<a name="20.1"></a>
<a name="commas--leading-trailing"></a>
-
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', };
<a name="20.2"></a>
<a name="commas--dangling"></a>
-
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 )