# CheckList
# 进行形式
项目迭代中:主要负责人以抽查浏览的形式快速审阅成员提交的代码,发现有问题的地方提出并打回改进。
团队定期:可以每周抽一个小时进行 code review + 后续的编写,针对 checklist 的某一个模块进行 review,成员之间互相审阅提交的编码,学习好的编码方式、探讨不好的编码的理由。
针对某几个模块 review,提出问题,然后再分配进行修改。1. review
- 熟悉模块功能。
# 代码风格
- ESLINT + Prettier
# 命名规范
常用命名规范有四种:
camelCase 驼峰式
PascalCase 帕斯卡命名式
kabab-case 短横线连接式
Snake 下划线连接式
变量名需要能够表明其含义,以小写字母开头,使用驼峰式命名法。
函数名也是一样,但是函数名应该以大写字母开头,这样便于和变量名区分开来。
# CSS 类名采用横线命名规范
推荐:
.block {
}
.block-element {
}
.block-element.modifier {
}
2
3
4
5
6
应用:
.ivu-form {
}
.ivu-form-item {
}
.ivu-form-item.active {
}
.ivu-form-item-label {
}
.ivu-form-item-content {
}
2
3
4
5
6
7
8
9
10
一般不超过四级,超过 4 级后,到第 5 级时,起步。
.ivu-xxxx第5级
# JS 命名规范
# 采用 Camel Case 小驼峰式命名
studentInfo;
# 针对常量,采用全大写+下划线形式
const TIMES = 10;
# 避免名称冗余
推荐:
const Car = {
make: "Honda",
model: "Accord",
color: "Blue",
};
2
3
4
5
不推荐:
const Car = {
carMake: "Honda",
carModel: "Accord",
carColor: "Blue",
};
2
3
4
5
应用:
const formModalStatus = {
add: false,
edit: false,
};
2
3
4
# Vue 命名规范
# 文件
.js
文件, 除 index.js 外,其他都采用 camelCase 风格,如export2Excel.js
.vue
文件, 除 index.vue 外,其他统一用 PascalCase 风格, 如VerticalNav.vue
.scss
文件, 除 index.scss 外,其他统一用 camelCase 风格,如controlBorderWarnPanel.scss
组件名采用大写字母开头的驼峰式命名
# 命名符合语义化
命名需要符合语义化,如果函数命名
,可以采用加上动词前缀:
动词 | 含义 |
---|---|
can | 判断是否可执行某个动作 |
has | 判断是否含有某个值 |
is | 判断是否为某个值 |
get | 获取某个值 |
set | 设置某个值 |
set | 设置某个值 |
推荐:
// 是否可阅读
function CanRead() {
return true;
}
// 获取姓名
function GetName() {
return this.name;
}
2
3
4
5
6
7
8
9
另外,针对处于类编码风格(TS + Vue)里的函数名统一首字母大写,以便区分变量名与函数名。
# JS 推荐写法
# 每个常量都需命名
每个常量应该命名,不然看代码的人不知道这个常量
表示什么意思。
推荐:
const COL_NUM = 10;
let row = Math.ceil(num / COL_NUM);
2
不推荐:
let row = Math.ceil(num / 10);
对于多个状态的常量,抽离成一个对象进行枚举。
const templateType = {
extend: 0,
system: 1,
};
const templates = {
[this.templateType.extend]: "",
[this.templateType.system]: "",
};
2
3
4
5
6
7
8
9
# Modal 框的控制
Before
html
<Modal v-model="ysjCatalogModalStatus.add"></Modal>
let add = false;
let edit = false;
let delete = false;
let showTemplate = false;
2
3
4
After 1,进行适当的层级处理,更具可读性
private ysjCatalogModalStatus = {
add: false,
edit: false,
delete: false,
showTemplate: false
};
2
3
4
5
6
控制显示
// hide
this.ysjCatalogModalStatus.add = true;
// show
this.ysjCatalogModalStatus.add = false;
2
3
4
After2,使用一个 modelType 变量以及 map 组合,更加容易管理,而不用设置 true 或 false。适用于默认只显示一个弹框的情况下。
<Modal v-model="modelType === modelTypeMap.add"></Modal>
let modelTypeMap = {
add: "add",
edit: "edit",
delete: "delete",
showTemplate: "showTemplate",
};
let modelType = "";
2
3
4
5
6
7
控制显示
// hide
this.modelType = "";
// show
this.modelType = this.modelTypeMap.add;
2
3
4
# 推荐使用字面量
创建对象和数组推荐使用字面量,因为这不仅是性能最优(js 为什么说对象字面量赋值比 new Object()高效?)也有助于节省代码量。
good
let obj = {
name: "tom",
age: 15,
sex: "男",
};
2
3
4
5
不推荐:
let obj = {};
obj.name = "tom";
obj.age = 15;
obj.sex = "男";
2
3
4
# 对象设置默认属性的推荐写法
推荐 1:
const menuConfig = {
title: "Order",
// User did not include 'body' key
buttonText: "Send",
cancellable: true,
};
function createMenu(config) {
config = Object.assign(
{
title: "Foo",
body: "Bar",
buttonText: "Baz",
cancellable: true,
},
config
);
// config now equals: {title: "Order", body: "Bar", buttonText: "Send", cancelable}
}
createMenu(menuConfig);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
推荐 2:
const menuConfig = {
title: "Order",
// User did not include 'body' key
buttonText: "Send",
cancellable: true
}
function createMenu({title = "Foo", body = "Bar", buttonText: "Baz", cancellable = true}) {
// config now equals: {title: "Order", body: "Bar", buttonText: "Send", cancelable}
}
createMenu(menuConfig);
2
3
4
5
6
7
8
9
10
11
推荐 1 和推荐 2 都是把默认属性内置到函数里面,这样这个函数就不会受到外部状态的影响,由参数决定。
不推荐:
const menuConfig = {
title: null,
body: "Bar",
buttonText: null,
cancellable: true,
};
function createMenu(config) {
config.title = config.title || "Foo";
config.body = config.body || "Bar";
config.buttonText = config.buttonText || "Baz";
config.cancellable =
config.cancellable !== undefined ? config.cancellable : true;
}
createMenu(menuConfig);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 遍历
- 使用 map。
- 临时数组
# 相同功能的业务逻辑放在一块
// 元数据
// del
// add
// edit
// 字典
2
3
4
5
# 函数参数写法
函数参数越少越好,如果参数超过两个,要使用 ES6
的解构语法,不用考虑参数的顺序。
推荐:
function createMenu({ title, body, buttonText, cancellable }) {
// ...
}
createMenu({
title: "Foo",
body: "Bar",
buttonText: "Baz",
cancellable: true,
});
2
3
4
5
6
7
8
9
10
# 使用函数默认值
使用参数默认值替代使用条件语句进行赋值。
推荐:
function createMicrobrewery(name = "Hipster Brew Co.") {
//...
}
2
3
不推荐:
function createMicrobrewery(name) {
const breweryName = name || "Hipster Brew Co.";
}
2
3
# 最小函数准则
避免函数过长,可以把函数拆分为更小的函数。可以遵循这样的原则:每当感觉需要以注释来说明点什么的时候,我们就把需要说明的东西写进一个独立函数中,并以其用途(而非实现手法)命名。关键不在于函数的长度,而在于函数“做什么”和“如何做”之间的语义距离。
Before:
void printOwing(double amount) {
printBanner();
// print details
System.out.println("name: " + _name);
System.out.println("amount: " + _amount);
}
2
3
4
5
6
7
After:
void printOwing(double amount) {
printBanner(amount); // 把参数传递过去
}
// 命名是什么:打印细节,而不是做什么:打印name 和 amout
void printDetails(double amount) {
System.out.println("name: " + _name);
System.out.println("amount: " + _amount);
}
2
3
4
5
6
7
8
除了注释,条件表达式和循环常常也是提炼的信号。
# 推荐函数式编程
过程式的编程是把过程具体的流程描述出来,而函数式编程更多是描述性,并且不依赖外部状态的纯函数,举个例子,使用 map 是函数式编程(传入一个回调函数),而使用 for 循环则是过程式编程,需要把具体的流程编写出来。
函数式编程使用的一些技术:
- 头等函数,函数可以像对象一样使用,参数传递、reture 出去、赋值、嵌套等。
- 递归&尾递归(复用调用栈),写递归要注意事项:
- 爆栈
- 重复计算
- 循环引用
- pipeline 管道
- 柯里化(复用参数、延迟执行)
- 高阶函数(尽量使用 map、reduce、filter 代替普通的循环)
# map&reduce
推荐:
const programmerOutput = [
{
name: "Uncle Bobby",
linesOfCode: 500,
},
{
name: "Suzie Q",
linesOfCode: 1500,
},
{
name: "Gracie Hopper",
linesOfCode: 1000,
},
];
let totalOutput = programmerOutput
.map((output) => output.lineOfCode)
.reduce((totalLines, lines) => totalLines + lines, 0);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
不推荐:
const programmerOutput = [
{
name: "Uncle Bobby",
linesOfCode: 500,
},
{
name: "Suzie Q",
linesOfCode: 1500,
},
{
name: "Gracie Hopper",
linesOfCode: 1000,
},
];
let totalOutput = 0;
for (let i = 0; i < programmerOutput.length; i++) {
totalOutput += programmerOutput[i].linesOfCode;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
应用:
/**
* 处理进度条样式
*/
private ProgressStyle(row: any) {
const style: any = {};
style.left = `${row.uploadProgress - 100}%`;
style.height = `${this.rowHeights[row._index]}px`; // 获取行高
style.top = `${this.rowHeights
.filter((item, index) => index < row._index)
.reduce((item, sum) => item + sum, 0)}px`; // 过滤高度
return style;
}
2
3
4
5
6
7
8
9
10
11
12
13
# 使用多态替换条件语句
遵循原则:策略模式 > switch > if
# 内存泄漏
- 定时器是否在不使用时清除,如
setTimeout
和setInterval
。 - 事件监听器(addEventListener、EventBus.emit)
# SCSS 推荐写法
# CSS 布局
- 遵循原则:flex 布局 > calc() > position: absolute
# Vue 项目规范
# 使用动态组件代替 v-if 渲染
推荐:
<transition enter-active-class="fadeIn">
<component v-bind:is="currentTabComponent"></component>
</transition>
<script lang="ts">
private tabsNav = [
{
label: "元数据",
value: YSJ
},
{
label: "字典表",
value: DictionaryTable
}
];
get currentTabComponent() {
const tab: any = this.tabsNav.find(
(item: any) => this.activeTab === item.label
);
return tab.value;
}
<script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
不推荐:
<div class="ysjgl-body">
<transition enter-active-class="fadeIn">
<div class="tab-box" v-if="activeTab === '元数据'">
<YSJ></YSJ>
</div>
</transition>
<transition enter-active-class="fadeIn">
<div class="tab-box" v-if="activeTab === '字典表'">
<dictionary-table></dictionary-table>
</div>
</transition>
</div>
2
3
4
5
6
7
8
9
10
11
12
# 少见的控制结构
# Return 语句
# 递归调用
# 异常处理
# Vue 项目规范
# TS 项目规范
# 其他
# 尽量不手动操作 DOM
# 删除弃用代码
因为团队现在使用 vue
框架,所以在项目开发中尽量使用 vue
的特性去满足我们的需求,尽量不要手动操作 DOM
,包括:增删改 dom
元素、以及更改样式、添加事件等。
# 编码规范
# 注释规范
# 参考资料
ES5 →