前言
不知不觉,已经工作接近5年了,项目大大小小也做了不少,虽然每个项目自己都是深度参与,但当我回看以前的代码时,还是会惊呼 [😲这是啥意思?是我写的吗?怎么看不懂], 于是开始关注自己的代码质量,今天把我这几年对于代码质量的心得做一个总结
好的代码就像一份好的报纸📰,题目就是整篇内容的缩写,而且内容要凝练清晰,上下逻辑联系紧密,不可拖拖拉拉,含糊不清,让人不知所云
命名
计算机科学中只有两个难题:缓存失效 和 命名 --Phil Karlton
函数命名
命名要偏向功能 ,而非执行过程,可以使用 前缀词 + [名词] + [动词]
前缀词部分总结:
说明 | 前缀词 | 举例 |
---|---|---|
是否符合状态 | is | isDialogOpen |
能否执行 | can | canUserActive |
是否包含 | has/include/contains | containsUserId |
是否需要 | should / need | needUsernameLogin |
过滤 | filter | filterByName |
合并 | merge | mergeConfig |
排序 | sort | sortByAmount |
转化 | to/convert | toUppderCase |
从对象/数据结构中获取数据 | get | getUserId |
计算获取数据 | cal | calUserAveragScore |
网络请求 | fetch | fetchUserInfo |
计算获取数据 | cal | calUserAveragScore |
解析数据,不能直接获取 | parse | parseUserInfo |
格式化 | format | formatDate |
切换 | toggle | toggleSelected |
新增 | add | addTag |
创建 | create | CreateInstance |
修改 | update | updateTag |
删除 | delete | deleteTagById |
移除 | remove | removeTagById |
add
是表示新增,比如对于一个文章来说,可以使用 addTag
往这个文章中新增一个标签
create
是创建实例,常用于实例化方法和工厂方法的命名
delete
在于删除数据,是不可恢复的,比如在列表中删除一个子项(虽然后端是逻辑删除,但是对于前端来说是不可恢复)
remove
是移除,比如给一个文章添加标签,这个标签可以移除掉,但是这个标签可以给其他文章使用
解释性变量 / 中间变量
一些变量是 只在函数中间使用, 但是有实际意义,避免过长的计算过程导致的心智负担
比如下面的这行代码,知道在干什么吗?🧞
js
let orderInfo = {
quanity:150,
price:3.7
}
function getTotalPrice (orderInfo) {
return orderInfo.quanity * orderInfo.price
- Math.max(0, orderInfo.quanity - 100 ) * orderInfo.price * 0.1
}
如果我们写成下面这样,是不是更加清晰了呢?
js
// 总价格为商品总价(单价 * 数量) - 折扣(超过 100 个打 9 折)
let orderInfo = {
quanity:150,
price:3.7
}
function getTotalPrice (orderInfo) {
// 基础金额
let baseSumMoney = orderInfo.quanity * orderInfo.price;
// 打折金额
let discountMoney = Math.max( 0, orderInfo.quanity - 100 ) * orderInfo.price * 0.1;
return baseSumMoney - discountMoney
}
像 baseSumMoney
和 discountMoney
都属于 解释型变量
解释型变量大大提高了可读性,比如我们也可以在循环中使用
js
fruits.map(f=> doSomeing(f))
如果这个 循环代码量特别多,是不是停下来思考一下这个 f
是什么意思
如果我们改为下面这种,会不会好些呢?
js
fruits.map(fruit=> doSomeing(fruit))
还有就是 ts 中的 boolean 值的命名,你也许会写出下面的ts类型,只知道会是一个带 boolean 的 Promise, 但是不知道 boolean 是指代的什么
ts
type UserInfo = Promise<boolean>
如果我们把 boolean
用一个有意义的变量来命名,是不是会变得更清晰⚔️
ts
type CanActive = boolean;
type UserInfo = Promise<CanActive>
带单位的变量
比如有这样的一个节流函数
js
function throttle(
fn,
delay // 无法确定 delay 是什么单位
){}
看不出 delay
可以传递什么,是 [ 毫秒 ] 还是 [ 秒 ] 呢?
js
function throttle(
fn,
delaySeconds
){}
这样写是不是就知道要传什么了吧
数字
一些能够描述 数字意义 的词语,可以使用驼峰命名 比如: min,max,total 等等
js
const minBugs = 1
const maxBugs = 5;
const totalBugs = 3
const numberOfStudents = 20;
有时也要根据上下文使用合适的单位🎁
js
let minuteCount = 120;
let distanceInMeters = 500;
常量
使用 const 并且全部大写,命名只能使用下划线
js
cosnt PI = 3.14;
函数
函数的命名在前面已经说过了,接下来是函数的其他方面
尽量使用 纯函数,使用纯函数的好处就不多说了,说一个比较坑的例子
js
let obj = {
name:"lisi"
}
function a(obj){
obj.name = 'zs'
}
a(obj)
猜猜现在 obj.name
是 zs
还是 lisi
?
是 zs
!!
对于引用传递要当心💔
函数的要点
- 函数的形参数量要少于 3 个,否则可以使用对象形式传递
如果形参过多,对调用者就会造成很大的心智负担
- 函数要么做事,要么回答问题
是函数拆分的重要依据,如果无法精确的起一个函数名的话,说明可以再拆分
- 函数无副作用,不影响外部变量 比如添加一个 item
js
const addItemToCart =(cart,item)=>{
return [...cart,{item}]
}
代码格式
- 应该像读报纸,顶部给出高级的算法和概念,细节依次展开
- 所有的变量统一写到最上面
- 代码组之间添加空白行
比如
js
function Clone() {
var clone,copy,
i = 1,
target = arguments[0] || {},
length = arguments.length;
if (typeof target === "boolean") {
target = arguments[1] || {};
}
for (; i < length; i++) {
if((options = arguments[ i ] ) !== null)
for (name in options) {
copy = options[ name ]
if (typeof copy == "object"){
clone = {}
Clone(clone, copy)
} else {
target[ name ] = copy;
}
}
}
return target
}
总之代码要整洁大气
注释
如果可以使用变量名来解释,就不要使用注释
如果非要使用注释,可以使用 jsDoc
来提供更多信息
param
你可以在变量说明前加个连字符,使之更加容易阅读
js
/**
* @param {string} somebody - Somebody's name.
*/
function sayHello(somebody) {
alert('Hello ' + somebody);
}
可选参数
js
/**
* @param {string} [somebody] - Somebody's name.
*/
function sayHello(somebody) {
if (!somebody) {
somebody = 'John Doe';
}
alert('Hello ' + somebody);
}
默认参数
js
/**
* @param {string} [somebody=John Doe] - Somebody's name.
*/
function sayHello(somebody) {
if (!somebody) {
somebody = 'John Doe';
}
alert('Hello ' + somebody);
}
联合类型
js
/**
* @param {'GET' | 'POST'} method 请求方法
*/
function m( method ){}
数组对象
js
/**
* Assign the project to a list of employees.
* @param {Array.<{ name: string, department: string }>} employees - The employees
*/
function assignProjectToEmployees(employees) {
// ...
}
普通对象
js
/**
* Assign the project to an employee.
* @param {Object} employee - The employee who is responsible for the project.
* @param {string} employee.name - The name of the employee.
* @param {string} employee.department - The employee's department.
*/
function Project (employee) {
// ...
}
@example
对函数的使用进行举例说明
js
/**
* @example
*
* var object = { 'a': 1 };
* var other = { 'a': 1 };
*
* _.eq(object, object);
* // => true
*
*/
ts中可以使用md语法做注释
ts
/**
*
@description ### 填充模式
- stretch 拉伸充满
- cover 裁切充满,保持图片比例
- contain 全部显示,留白,保持图片比例 */
type mode = "stretch" | "cover" | "contain";
结束
现在只想到这么多,如果以后有什么新的心得,还会继续更新⚓⚓⚓