<一> React 代码规范
文件与组件命名
- 扩展名: 使用.js作为js文件的扩展名。如果同一个文件夹下有同名而不同作用的js文件,则通过中缀(小写)进一步区分,例如:HomePageView.component.js, HomePageView.style.js, HomePageView.action.js等
- 文件名: 使用驼峰命名法且首字母大写,如HomePageView.js
- 组件命名: 与文件名(除中缀外)完全一致。如果组件单独放置在目录中,则目录名也一致
1
|
import Footer from
'./Component/OrderAccount/OrderAccountView'
;
|
1
|
import Footer from
'./Component/OrderAccount/OrderAccount'
;
|
1
|
import Footer from
'./OrderAccount'
;
|
组件声明
- 使用class与extends关键字。不使用React.createClass方法。需要导出的组件直接在class关键字前使用export default。
1
|
export
default
React.createClass({ });
|
1
|
export
default
class HomePageView extends Component { }
|
对齐
- 按下面的案例对齐
1
2
|
<Foo superLongParam=
"bar"
anotherSuperLongParam=
"baz"
/>
|
1
2
|
<Foo superLongParam=
"bar"
anotherSuperLongParam=
"baz"
/>
|
// 如果一行能摆下props,那就摆在一行
1
|
<Foo bar=
"bar"
/>
|
// 子组件照常缩进
1
2
3
4
5
6
|
<Foo
superLongParam=
"bar"
anotherSuperLongParam=
"baz"
>
<Spazz />
</Foo>
|
引号
- 对于JSX的字符串属性使用双引号("),其他情况下使用单引号。
1
|
<Foo bar=
'bar'
/>
|
1
|
<Foo bar=
"bar"
/>
|
1
|
<Foo style={{ left:
"20px"
}} />
|
1
|
<Foo style={{ left:
'20px'
}} />
|
空格
- 在自闭合的标签中包含一个空格。
1
|
<Foo/>
|
1
|
<Foo />
|
1
|
<Foo />
|
1
|
<Foo />
|
state/props
- 对于多个单词组成的pros,使用驼峰命名法。不使用下划线或连接线。
1
2
3
4
|
<Foo
UserName=
"hello"
phone_number={12345678}
/>
|
1
2
3
4
|
<Foo
userName=
"hello"
phoneNumber={12345678}
/>
|
- 读取state和props时,使用const与解构,必要时可使用let。不使用var。
1
2
|
var
userName =
this
.props.userName;
let checked =
this
.state.checked;
|
1
2
|
const { userName, age, sex } =
this
.props;
const { checked } =
this
.state;
|
括号
- 当JSX标签超过一行时,使用括号包裹。
1
2
3
4
5
|
render() {
return
<MyComponent className=
"long body"
foo=
"bar"
>
<MyChild />
</MyComponent>;
}
|
1
2
3
4
5
6
7
|
render() {
return
(
<MyComponent className=
"long body"
foo=
"bar"
>
<MyChild />
</MyComponent>
);
}
|
// good, when single line
1
2
3
4
|
render() {
const body = <div>hello</div>;
return
<MyComponent>{body}</MyComponent>;
}
|
标签
- 对于没有子组件的JSX标签,始终自闭合。
1
|
<Foo className=
"stuff"
></Foo>
|
1
|
<Foo className=
"stuff"
/>
|
-
如果组件有多行属性,则另起一行进行自闭合。
1
2
3
|
<Foo
bar=
"bar"
baz=
"baz"
/>
|
1
2
3
4
|
<Foo
bar=
"bar"
baz=
"baz"
/>
|
方法
- 为方法命名时,不使用下划线开头(哪怕是想用作私有方法)。
1
2
3
4
5
6
|
React.createClass({
_onClickSubmit() {
// do stuff
}
// other stuff
});
|
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进行声明
1
2
3
4
|
let someNum = 123;
const AnotherStr =
'不变的字符串'
;
let arr = [
'不'
,
'变'
,
'数'
,
'组'
];
var
ANOTHER_OBJ = {
'不变对象'
:
true
};
|
1
2
3
4
|
const someNum = 123;
const anotherStr =
'不变的字符串'
;
const arr = [
'不'
,
'变'
,
'数'
,
'组'
];
const anotherObj = {
'不变对象'
:
true
};
|
字符串
- 处理多行字符串,使用模板字符串
以反引号( ` )标示
可读性更强,代码更易编写
注意排版引起空格的问题,使用场景为声明HTML模板字符串
1
2
3
|
const tmpl =
'<div class="content"> \n'
+
'<h1>这是换行了。</h1> \n'
+
'</div>'
;
|
1
|
const tmpl = ` <div class=
"content"
> <h1>这是换行了。</h1> </div>`;
|
- 处理字符串拼接变量时,使用模板字符串
1
2
3
|
function
sayHi(name) {
return
'How are you, '
+ name +
'?'
;
}
|
1
2
3
|
function
sayHi(name) {
return
`How are you, ${name}?`;
}
|
解构
- 解构语句中不使用圆括号
1
2
|
[(a)] = [11];
// a未定义
let { a: (b) } = {};
// 解析出错
|
1
|
let [a, b] = [11, 22];
|
- 对象解构
对象解构 元素与顺序无关
对象指定默认值时仅对恒等于undefined ( !== null ) 的情况生效
- 若函数形参为对象时,使用对象解构赋值
1
2
3
4
5
|
function
someFun(opt) {
let opt1 = opt.opt1;
let opt2 = opt.opt2;
console.log(op1);
}
|
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);
}
|
- 若函数有多个返回值时,使用对象解构,不使用数组解构,避免添加顺序的问题
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
|
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
|
- 已声明的变量不能用于解构赋值(语法错误)
// 语法错误
1
|
let a; { a } = { b: 123};
|
- 数组解构
数组元素与顺序相关
- 交换变量的值
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];
// 交换变量
|
- 将数组成员赋值给变量时,使用数组解构
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进行转换
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));
}
|
- 数组拷贝
采用数组扩展...形式
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'
;
|