一汞舱、javascript代碼規(guī)范
-
變量
1.1 一直使用
const
來聲明變量唐瀑,如果不這樣做就會產(chǎn)生全局變量。我們需要避免全局命名空間的污染噪沙。地球隊長已經(jīng)警告過我們了炼彪。(譯注:全局,global 亦有全球的意思正歼。地球隊長的責任是保衛(wèi)地球環(huán)境辐马,所以他警告我們不要造成「全球」污染。)// bad superPower = new SuperPower(); // good const superPower = new SuperPower();
1.2 使用 const局义、let 聲明變量喜爷,而不使用 var冗疮。
-
數(shù)組
2.1 使用字面值創(chuàng)建數(shù)組。
// bad const items = new Array(); // good const items = [];
2.2 向數(shù)組添加元素時使用 Arrary#push 替代直接賦值檩帐。
const someStack = []; // bad someStack[someStack.length] = 'abracadabra'; // good someStack.push('abracadabra');
2.3 使用拓展運算符
...
復制數(shù)組术幔。// bad const len = items.length; const itemsCopy = []; let i; for (i = 0; i < len; i++) { itemsCopy[i] = items[i]; } // good const itemsCopy = [...items];
2.4 使用 Array#from 把一個類數(shù)組對象轉換成數(shù)組。
const foo = document.querySelectorAll('.foo'); const nodes = Array.from(foo);
-
字符串
3.1 字符串使用單引號
''
3.2 字符串過長時轿塔,使用+連接字符串
過度使用字串連接符號可能會對性能造成影響特愿。// 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.';
3.3 程序化生成字符串時,使用模板字符串代替字符串連接勾缭。
// bad function sayHi(name) { return 'How are you, ' + name + '?'; } // bad function sayHi(name) { return ['How are you, ', name, '?'].join(); } // good function sayHi(name) { return `How are you, ${name}?`; }
-
函數(shù)
4.1 永遠不要把參數(shù)命名為
arguments
。這將取代原來函數(shù)作用域內的arguments
對象目养。// bad function nope(name, options, arguments) { // ...stuff... } // good function yup(name, options, args) { // ...stuff... }
4.2 不要使用
arguments
俩由。可以選擇 rest 語法...
替代癌蚁。為什么幻梯?使用
...
能明確你要傳入的參數(shù)。另外 rest 參數(shù)是一個真正的數(shù)組努释,而arguments
是一個類數(shù)組碘梢。// bad function concatenateAll() { const args = Array.prototype.slice.call(arguments); return args.join(''); } // good function concatenateAll(...args) { return args.join(''); }
4.3 直接給函數(shù)的參數(shù)指定默認值,不要使用一個變化的函數(shù)參數(shù)伐蒂。
// really bad function handleThings(opts) { // 不煞躬!我們不應該改變函數(shù)參數(shù)。 // 更加糟糕: 如果參數(shù) opts 是 false 的話逸邦,它就會被設定為一個對象恩沛。 // 但這樣的寫法會造成一些 Bugs。 //(譯注:例如當 opts 被賦值為空字符串缕减,opts 仍然會被下一行代碼設定為一個空對象雷客。) opts = opts || {}; // ... } // still bad function handleThings(opts) { if (opts === void 0) { opts = {}; } // ... } // good function handleThings(opts = {}) { // ... }
4.4 除非參數(shù)過多,不然不要傳入一個對象
// bad function handleThings(user) { // ... return user.username == '' } // good function handleThings(username) { // ... return username == '' }
-
箭頭函數(shù)
5.1 當你必須使用函數(shù)表達式(或傳遞一個匿名函數(shù))時桥狡,使用箭頭函數(shù)符號搅裙。
為什么?因為箭頭函數(shù)創(chuàng)造了新的一個
this
執(zhí)行環(huán)境,通常情況下都能滿足你的需求裹芝,而且這樣的寫法更為簡潔部逮。為什么不?如果你有一個相當復雜的函數(shù)局雄,你或許可以把邏輯部分轉移到一個函數(shù)聲明上甥啄。
// bad [1, 2, 3].map(function (x) { return x * x; }); // good [1, 2, 3].map((x) => { return x * x; });
5.2 如果一個函數(shù)適合用一行寫出并且只有一個參數(shù),那就把花括號炬搭、圓括號和
return
都省略掉蜈漓。如果不是穆桂,那就不要省略。為什么融虽?語法糖享完。在鏈式調用中可讀性很高。
為什么不有额?當你打算回傳一個對象的時候般又。
// good [1, 2, 3].map(x => x * x); // good [1, 2, 3].reduce((total, n) => { return total + n; }, 0);
-
屬性
6.1 使用
.
來訪問對象的屬性。const luke = { jedi: true, age: 28, }; // bad const isJedi = luke['jedi']; // good const isJedi = luke.jedi;
6.2 當通過變量訪問屬性時使用中括號
[]
巍佑。const luke = { jedi: true, age: 28, }; function getProp(prop) { return luke[prop]; } const isJedi = getProp('jedi');
-
解構
7.1 使用解構存取和使用多屬性對象茴迁。
為什么?因為解構能減少臨時引用屬性萤衰。// bad function getFullName(user) { const firstName = user.firstName; const lastName = user.lastName; return `${firstName} ${lastName}`; } // good function getFullName(obj) { const { firstName, lastName } = obj; return `${firstName} ${lastName}`; } // best function getFullName({ firstName, lastName }) { return `${firstName} ${lastName}`; }
7.2 對數(shù)組使用解構賦值堕义。
const arr = [1, 2, 3, 4]; // bad const first = arr[0]; const second = arr[1]; // good const [first, second] = arr;
7.3 需要回傳多個值時,使用對象解構脆栋,而不是數(shù)組解構倦卖。
為什么?增加屬性或者改變排序不會改變調用時的位置椿争。
// bad function processInput(input) { // then a miracle occurs return [left, right, top, bottom]; } // 調用時需要考慮回調數(shù)據(jù)的順序怕膛。 const [left, __, top] = processInput(input); // good function processInput(input) { // then a miracle occurs return { left, right, top, bottom }; } // 調用時只選擇需要的數(shù)據(jù) const { left, right } = processInput(input);
-
比較運算符 & 等號
8.1
優(yōu)先使用
=== 和 !==
而不是
== 和 !=
8.2 條件表達式例如 if 語句通過抽象方法
ToBoolean
強制計算它們的表達式并且總是遵守下面的規(guī)則:- 對象 被計算為
true
-
Undefined
被計算為false
-
Null
被計算為false
-
Boolean
被計算為true
或false
- 數(shù)字 如果是
+0
、-0
秦踪、或NaN
被計算為false
, 否則為true
- 字符串 如果是空字符串
''
被計算為false
褐捻,否則為true
if ([0]) { // true // An array is an object, objects evaluate to true }
- 對象 被計算為
-
注釋
9.1 使用
/** ... */
作為多行注釋。包含描述洋侨、指定所有參數(shù)和返回值的類型和值舍扰。// bad // make() returns a new element // based on the passed in tag name // // @param {String} tag // @return {Element} element function make(tag) { // ...stuff... return element; } // good /** * make() returns a new element * based on the passed in tag name * * @param {String} tag * @return {Element} element */ function make(tag) { // ...stuff... return element; }
9.2 使用
//
作為單行注釋。在評論對象上面另起一行使用單行注釋希坚。在注釋前插入空行边苹。9.3
//
符號后添加一個空格9.4 方法使用jsdoc的方式注釋
-
分號
10.1 匿名方法后必須使用分號
代碼壓縮后如果多個匿名方法壓縮在一起會變成代碼錯誤。
-
命名規(guī)制
11.1 避免單字母命名裁僧。命名應具備描述性个束。
// bad function q() { // ...stuff... } // good function query() { // ..stuff.. }
11.2 使用駝峰式命名對象、函數(shù)和實例聊疲。
// bad const OBJEcttsssss = {}; const this_is_my_object = {}; function c() {} // good const thisIsMyObject = {}; function thisIsMyFunction() {}
11.3 使用帕斯卡式命名構造函數(shù)或類茬底。
// bad function user(options) { this.name = options.name; } const bad = new user({ name: 'nope', }); // good class User { constructor(options) { this.name = options.name; } } const good = new User({ name: 'yup', });
-
原型鏈
12.1 盡量避免覆蓋原型鏈的方式修改javascript基礎對象,如String获洲、Date
-
模塊
13.1 總是使用模組 (
import
/export
) 而不是其他非標準模塊系統(tǒng)阱表。你可以編譯為你喜歡的模塊系統(tǒng)。// 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;
二、React/JSX
-
Declaration 聲明模塊
使用
class extends React.Component
而不是React.createClass
,除非你有充足的理由來使用這些方法.// bad const Listing = React.createClass({ // ... render() { return <div>{this.state.hello}</div>; } }); // good class Listing extends React.Component { // ... render() { return <div>{this.state.hello}</div>; } }
-
Alignment 代碼對齊
2.1 遵循以下的JSX語法縮進/格式. eslint:
react/jsx-closing-bracket-location
// bad <Foo superLongParam="bar" anotherSuperLongParam="baz" /> // good, 有多行屬性的話, 新建一行關閉標簽 <Foo superLongParam="bar" anotherSuperLongParam="baz" /> // 若能在一行中顯示, 直接寫成一行 <Foo bar="bar" /> // 子元素按照常規(guī)方式縮進 <Foo superLongParam="bar" anotherSuperLongParam="baz" > <Quux /> </Foo>
-
Quotes 單引號還是雙引號
3.1 對于JSX屬性值總是使用雙引號(
"
), 其他均使用單引號('
).
為什么? HTML屬性也是用雙引號, 因此JSX的屬性也遵循此約定.
-
Spacing 空格
4.1 總是在自動關閉的標簽前加一個空格最爬,正常情況下也不需要換行. eslint:
no-multi-spaces
,react/jsx-space-before-closing
// bad <Foo/> // very bad <Foo /> // bad <Foo /> // good <Foo />
4.2 不要在JSX
{}
引用括號里兩邊加空格. eslint:react/jsx-curly-spacing
// bad <Foo bar={ baz } /> // good <Foo bar={baz} />
-
Props 屬性
5.1 JSX屬性名使用駱駝式風格
camelCase
.// bad <Foo UserName="hello" phone_number={12345678} /> // good <Foo userName="hello" phoneNumber={12345678} />
5.2 對于所有非必須的屬性涉馁,總是手動去定義
defaultProps
屬性.為什么? propTypes 可以作為模塊的文檔說明, 并且聲明 defaultProps 的話意味著閱讀代碼的人不需要去假設一些默認值。更重要的是, 顯示的聲明默認屬性可以讓你的模塊跳過屬性類型的檢查.
// bad function SFC({ foo, bar, children }) { return <div>{foo}{bar}{children}</div>; } SFC.propTypes = { foo: PropTypes.number.isRequired, bar: PropTypes.string, children: PropTypes.node, }; // good function SFC({ foo, bar }) { return <div>{foo}{bar}</div>; } SFC.propTypes = { foo: PropTypes.number.isRequired, bar: PropTypes.string, }; SFC.defaultProps = { bar: '', children: null, };
-
Parentheses 括號
6.1 將多行的JSX標簽寫在
()
里. eslint:react/wrap-multilines
// bad render() { return <MyComponent className="long body" foo="bar"> <MyChild /> </MyComponent>; } // good render() { return ( <MyComponent className="long body" foo="bar"> <MyChild /> </MyComponent> ); } // good, 單行可以不需要 render() { const body = <div>hello</div>; return <MyComponent>{body}</MyComponent>; }
-
Tags 標簽
7.1 對于沒有子元素的標簽來說總是自己關閉標簽. eslint:
react/self-closing-comp
// bad <Foo className="stuff"></Foo> // good <Foo className="stuff" />
7.2 如果模塊有多行的屬性爱致, 關閉標簽時新建一行. eslint: react/jsx-closing-bracket-location
// bad
<Foo
bar="bar"
baz="baz" />
// good
<Foo
bar="bar"
baz="baz"
/>
-
Methods 函數(shù)
8.1 當在
render()
里使用事件處理方法時烤送,提前在構造函數(shù)里把this
綁定上去. eslint:react/jsx-no-bind
// bad class extends React.Component { onClickDiv() { // do stuff } render() { return <div onClick={this.onClickDiv.bind(this)} /> } } // good class extends React.Component { constructor(props) { super(props); this.onClickDiv = this.onClickDiv.bind(this); } onClickDiv() { // do stuff } render() { return <div onClick={this.onClickDiv} /> } } // good class extends React.Component { constructor(props) { super(props); } onClickDiv = () => { // do stuff } render() { return <div onClick={this.onClickDiv} /> } }
8.2 在
render
方法中總是確保return
返回值. eslint:react/require-render-return
// bad render() { (<div />); } // good render() { return (<div />); }
-
Ordering React 模塊生命周期
主要規(guī)范組件內部方法的定義順序。
Es6 class 定義規(guī)范:
static 方法 constructor getChildContext componentWillMount componentDidMount componentWillReceiveProps shouldComponentUpdate componentWillUpdate componentDidUpdate componentWillUnmount clickHandlers + eventHandlers 如 onClickSubmit() 或 onChangeDescription() getter methods for render 如 getSelectReason() 或 getFooterContent() render methods 如 renderNavigation() 或 renderProfilePicture() render
以 Es6 Class 定義的組件為例
class Person extends React.Component { static defaultProps = {} static propTypes = {} // 構造函數(shù) constructor (props) { super(props); // 定義 state this.state = { smiling: false }; } // 生命周期方法 componentWillMount () {} componentDidMount () {} componentWillUnmount () {} // getters and setters get attr() {} // handlers handleClick = () => {} // render renderChild() {} render () {} }