<一> React 代碼規范
文件與組件命名
- 擴展名: 使用.js作為js文件的擴展名。如果同一個文件夾下有同名而不同作用的js文件,則通過中綴(小寫)進一步區分,例如:HomePageView.component.js, HomePageView.style.js, HomePageView.action.js等
- 文件名: 使用駝峰命名法且首字母大寫,如HomePageView.js
- 組件命名: 與文件名(除中綴外)完全一致。如果組件單獨放置在目錄中,則目錄名也一致
Bad Code
1
|
import Footer from
'./Component/OrderAccount/OrderAccountView'
;
|
Good Code
1
|
import Footer from
'./Component/OrderAccount/OrderAccount'
;
|
Good Code
1
|
import Footer from
'./OrderAccount'
;
|
組件聲明
- 使用class與extends關鍵字。不使用React.createClass方法。需要導出的組件直接在class關鍵字前使用export default。
Bad Code
1
|
export
default
React.createClass({ });
|
Good Code
1
|
export
default
class HomePageView extends Component { }
|
對齊
- 按下面的案例對齊
Bad Code
1
2
|
<Foo superLongParam=
"bar"
anotherSuperLongParam=
"baz"
/>
|
Good Code
1
2
|
<Foo superLongParam=
"bar"
anotherSuperLongParam=
"baz"
/>
|
// 如果一行能擺下props,那就擺在一行
Bad Code
1
|
<Foo bar=
"bar"
/>
|
// 子組件照常縮進
Good Code
1
2
3
4
5
6
|
<Foo
superLongParam=
"bar"
anotherSuperLongParam=
"baz"
>
<Spazz />
</Foo>
|
引號
- 對於JSX的字符串屬性使用雙引號("),其他情況下使用單引號。
Bad Code
1
|
<Foo bar=
'bar'
/>
|
Good Code
1
|
<Foo bar=
"bar"
/>
|
Bad Code
1
|
<Foo style={{ left:
"20px"
}} />
|
Good Code
1
|
<Foo style={{ left:
'20px'
}} />
|
空格
- 在自閉合的標簽中包含一個空格。
Bad Code
1
|
<Foo/>
|
Bad Code
1
|
<Foo />
|
Bad Code
1
|
<Foo />
|
Good Code
1
|
<Foo />
|
state/props
- 對於多個單詞組成的pros,使用駝峰命名法。不使用下划線或連接線。
Bad Code
1
2
3
4
|
<Foo
UserName=
"hello"
phone_number={12345678}
/>
|
Good Code
1
2
3
4
|
<Foo
userName=
"hello"
phoneNumber={12345678}
/>
|
- 讀取state和props時,使用const與解構,必要時可使用let。不使用var。
Bad Code
1
2
|
var
userName =
this
.props.userName;
let checked =
this
.state.checked;
|
Good Code
1
2
|
const { userName, age, sex } =
this
.props;
const { checked } =
this
.state;
|
括號
- 當JSX標簽超過一行時,使用括號包裹。
Bad Code
1
2
3
4
5
|
render() {
return
<MyComponent className=
"long body"
foo=
"bar"
>
<MyChild />
</MyComponent>;
}
|
Good Code
1
2
3
4
5
6
7
|
render() {
return
(
<MyComponent className=
"long body"
foo=
"bar"
>
<MyChild />
</MyComponent>
);
}
|
// good, when single line
Good Code
1
2
3
4
|
render() {
const body = <div>hello</div>;
return
<MyComponent>{body}</MyComponent>;
}
|
標簽
- 對於沒有子組件的JSX標簽,始終自閉合。
Bad Code
1
|
<Foo className=
"stuff"
></Foo>
|
Good Code
1
|
<Foo className=
"stuff"
/>
|
-
如果組件有多行屬性,則另起一行進行自閉合。
Bad Code
1
2
3
|
<Foo
bar=
"bar"
baz=
"baz"
/>
|
Good Code
1
2
3
4
|
<Foo
bar=
"bar"
baz=
"baz"
/>
|
方法
- 為方法命名時,不使用下划線開頭(哪怕是想用作私有方法)。
Bad Code
1
2
3
4
5
6
|
React.createClass({
_onClickSubmit() {
// do stuff
}
// other stuff
});
|
Good Code
1
2
3
4
5
6
|
class extends React.Component {
onClickSubmit() {
// do stuff
}
// other stuff
});
|
方法聲明的順序
- 原則上按如下順序排列React組件的各個方法(生命周期):
<二>ES6代碼規范
變量與常量聲明
- 變量
盡量使用let來代替var
對於全局變量聲明,采用global.xxx = xxx,但應避免聲明過多全局變量污染環境
- 常量
對於常量應使用const進行聲明,命名采用駝峰寫法
對於使用 immutable 數據應用const進行聲明
Bad Code
1
2
3
4
|
let someNum = 123;
const AnotherStr =
'不變的字符串'
;
let arr = [
'不'
,
'變'
,
'數'
,
'組'
];
var
ANOTHER_OBJ = {
'不變對象'
:
true
};
|
Good Code
1
2
3
4
|
const someNum = 123;
const anotherStr =
'不變的字符串'
;
const arr = [
'不'
,
'變'
,
'數'
,
'組'
];
const anotherObj = {
'不變對象'
:
true
};
|
字符串
- 處理多行字符串,使用模板字符串
以反引號( ` )標示
可讀性更強,代碼更易編寫
注意排版引起空格的問題,使用場景為聲明HTML模板字符串
Bad Code
1
2
3
|
const tmpl =
'<div class="content"> \n'
+
'<h1>這是換行了。</h1> \n'
+
'</div>'
;
|
Good Code
1
|
const tmpl = ` <div class=
"content"
> <h1>這是換行了。</h1> </div>`;
|
- 處理字符串拼接變量時,使用模板字符串
Bad Code
1
2
3
|
function
sayHi(name) {
return
'How are you, '
+ name +
'?'
;
}
|
Good Code
1
2
3
|
function
sayHi(name) {
return
`How are you, ${name}?`;
}
|
解構
- 解構語句中不使用圓括號
Bad Code
1
2
|
[(a)] = [11];
// a未定義
let { a: (b) } = {};
// 解析出錯
|
Good Code
1
|
let [a, b] = [11, 22];
|
- 對象解構
對象解構 元素與順序無關
對象指定默認值時僅對恆等於undefined ( !== null ) 的情況生效
- 若函數形參為對象時,使用對象解構賦值
Bad Code
1
2
3
4
5
|
function
someFun(opt) {
let opt1 = opt.opt1;
let opt2 = opt.opt2;
console.log(op1);
}
|
Good Code
1
2
3
4
5
6
7
|
function
someFun(opt) {
let { opt1, opt2 } = opt;
console.log(`$(opt1) 加上 $(opt2)`);
}
function
someFun({ opt1, opt2 }) {
console.log(opt1);
}
|
- 若函數有多個返回值時,使用對象解構,不使用數組解構,避免添加順序的問題
Bad Code
1
2
3
4
5
6
|
function
anotherFun() {
const one = 1, two = 2, three = 3;
return
[one, two, three];
}
const [one, three, two] = anotherFun();
// 順序亂了
// one = 1, two = 3, three = 2
|
Good Code
1
2
3
4
5
6
|
function
anotherFun() {
const one = 1, two = 2, three = 3;
return
{ one, two, three };
}
const { one, three, two } = anotherFun();
// 不用管順序
// one = 1, two = 2, three = 3
|
- 已聲明的變量不能用於解構賦值(語法錯誤)
// 語法錯誤
Bad Code
1
|
let a; { a } = { b: 123};
|
- 數組解構
數組元素與順序相關
- 交換變量的值
Code
1
2
3
4
5
6
7
8
|
let x = 1; let y = 2;
// 不好
let temp;
temp = x;
x = y;
y = temp;
// 好
[x, y] = [y, x];
// 交換變量
|
- 將數組成員賦值給變量時,使用數組解構
Code
1
2
3
4
5
6
|
const arr = [1, 2, 3, 4, 5];
// 不好
const one = arr[0];
const two = arr[1];
// 好
const [one, two] = arr;
|
數組
- 將類數組(array-like)對象與可遍歷對象(如Set, Map)轉為真正數組
采用Array.from進行轉換
Code
1
2
3
4
5
6
7
8
|
// 不好
function
foo() {
let args = Array.prototype.slice.call(arguments);
}
// 好
function
foo() {
let args = Array.from(arguments);
}
|
- 數組去重
結合Set結構與Array.from
使用indexOf,HashTable等形式,不夠簡潔清晰
1
2
3
4
|
// 好
function
deduplication(arr) {
return
Array.from(
new
Set(arr));
}
|
- 數組拷貝
采用數組擴展...形式
Code
1
2
3
4
5
6
7
8
9
|
const items = [1, 2, 3];
// 不好
const len = items.length;
let copyTemp = [];
for
(let i = 0; i < len; i++) {
copyTemp[i] = items[i];
}
// 好
let copyTemp = [...items];
|
- 將一組數值轉為數組
采用Array.of進行轉換
1
2
3
4
5
6
|
// 不好
let arr1 =
new
Array(2);
// [undefined x 2]
let arr2 =
new
Array(1, 2, 3);
// [1, 2, 3]
// 好
let arr1 = Array.of(2);
// [2]
let arr2 = Array.of(1, 2, 3);
// [1, 2, 3]
|
函數
- 當要用函數表達式或匿名函數時,使用箭頭函數(Arrow Functions)
箭頭函數更加簡潔,並且綁定了this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
// 不好
const foo =
function
(x) {
console.log(foo.name);
// 返回'' ,函數表達式默認省略name屬性
};
[1, 2, 3].map(
function
(x) {
return
x + 1;
});
var
testObj = {
name:
'testObj'
,
init() {
var
_this =
this
;
// 保存定義時的this引用
document.addEventListener(
'click'
,
function
() {
return
_this.doSth();
},
false
);
},
doSth() {
console.log(
this
.name);
}
};
// 好
const foo = (x) => {
console.log(foo.name);
// 返回'foo'
};
[1, 2, 3].map( (x) => {
return
x + 1;
});
var
testObj = {
name:
'testObj'
,
init() {
// 箭頭函數自動綁定定義時所在的對象
document.addEventListener(
'click'
, () =>
this
.doSth(),
false
);
},
doSth() {
console.log(
this
.name);
}
};
|
- 箭頭函數書寫約定
函數體只有單行語句時,允許寫在同一行並去除花括號
當函數只有一個參數時,允許去除參數外層的括號
1
2
3
4
5
6
|
// 好
const foo = x => x + x;
// 注意此處會隱性return x + x
const foo = (x) => {
return
x + x;
// 若函數體有花括號語句塊時須進行顯性的return
};
[1, 2, 3].map( x => x * x);
|
- 用箭頭函數返回一個對象,應用括號包裹
1
2
3
4
|
// 不好
let test = x => { x: x };
// 花括號會變成語句塊,不表示對象
// 好
let test = x => ({ x: x });
// 使用括號可正確return {x:x}
|
l 立即調用函數 IIFE
1
2
3
4
5
6
7
8
|
// 不好
function
foo(opts) {
opts = opts || {};
// 此處有將0,''等假值轉換掉為默認值的副作用
}
// 好
function
foo(opts = {}) {
console.log(
'更加簡潔,安全'
);
}
|
- 對象中的函數方法使用縮寫形式
更加簡潔
函數方法不要使用箭頭函數,避免this指向的混亂
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// 不好
const shopObj = {
des:
'對象模塊寫法'
,
foo:
function
() {
console.log(
this
.des);
}
};
const shopObj = {
des:
'對象模塊寫法'
,
foo: () => {
console.log(
this
.des);
// 此處會變成undefined.des,因為指向頂層模塊的this
}
};
// 好
const des =
'對象模塊寫法'
;
// 使用對象屬性值簡寫方式
const shopObj = {
des,
foo() {
console.log(
this
.des);
}
};
|
類
- 類名應使用帕斯卡寫法(PascalCased)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// 好
class SomeClass {
}
l 類名與花括號須保留一個空格間距
// 不好
class Foo{
constructor(){
// constructor
}
sayHi()
{
// 僅保留一個空格間距
}
}
// 好
class Foo {
constructor() {
// constructor
}
sayHi() {
// 僅保留一個空格間距
}
}
|
- 定義類時,方法的順序如下:
-
- constructor
- public get/set 公用訪問器,set只能傳一個參數
- public methods 公用方法,公用相關命名使用小駝峰式寫法(lowerCamelCase)
- private get/set 私有訪問器,私有相關命名應加上下划線 _ 為前綴
- private methods 私有方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
// 好
class SomeClass {
constructor() {
// constructor
}
get aval() {
// public getter
}
set aval(val) {
// public setter
}
doSth() {
// 公用方法
}
get _aval() {
// private getter
}
set _aval() {
// private setter
}
_doSth() {
// 私有方法
}
}
|
- 如果不是class類,不使用new
1
2
3
4
5
6
7
8
|
// 不好
function
Foo() {
}
const foo =
new
Foo();
// 好
class Foo {
}
const foo =
new
Foo();
|
- 使用真正意思上的類Class寫法,不使用prototype進行模擬擴展
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
Class更加簡潔,易維護
// 不好
function
Dog(names = []) {
this
._names = [...names];
}
Dog.prototype.bark =
function
() {
const currName =
this
._names[0];
alert(`one one ${currName}`);
}
// 好
class Dog {
constructor(names = []) {
this
._names = [...names];
}
bark() {
const currName =
this
._names[0];
alert(`one one ${currName}`);
}
}
|
- this的注意事項
子類使用super關鍵字時,this應在調用super之后才能使用
可在方法中return this來實現鏈式調用寫法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
class Foo {
constructor(x, y) {
this
.x = x;
this
.y = y;
}
}
// 不好
class SubFoo extends Foo {
constructor(x, y, z) {
this
.z = z;
// 引用錯誤
super
(x, y);
}
}
// 好
class SubFoo extends Foo {
constructor(x, y, z) {
super
(x, y);
this
.z = z;
// this 放在 super 后調用
}
setHeight(height) {
this
.height = height;
return
this
;
}
}
|
模塊
- 使用import / export來做模塊加載導出,不使用非標准模塊寫法
跟着標准走的人,運氣總不會太差
1
2
3
4
5
6
|
// 不好
const colors = require(
'./colors'
);
module.exports = color.lightRed;
// 好
import { lightRed } from
'./colors'
;
export
default
lightRed;
|
- import / export 后面采用花括號{ }引入模塊的寫法時,須在花括號內左右各保留一個空格
1
2
3
4
5
|
// 不好
import {lightRed} from
'./colors'
;
import { lightRed} from
'./colors'
;
// 好
import { lightRed } from
'./colors'
;
|