写出优雅质量好的代码,应该统一好:规范、命名、注释、代码优雅
如果把些执行起来,加上合理的code review,就不会让后面接手同事,或者过一段时间,突然大声质问这TM谁写的代码,这么烂,查一下log,不可能,怎么可能是我自己写的。
规范
要规范,则要如,Prettier、ESLint、stylelint,这些工具的辅助,在第一层就可以把习惯不统一的代码全部强制统一,eslint不通过,不让提交,在阅读代码层面上来看,就不会出现有的2个缩进,有的4个缩进,有的有分号,有的没有分号;
// 统一eslint
arrayUnique (array) {
if (array && array.length) {
return [...new Set(...array)]
}
}
// 不要有多种风格,如这种
arrayUnique(array)
if(array && array.length)
return [...new Set(...array)]
}
}
// 这种
arrayUnique(array)
if(array && array.length)
return [...new Set(...array)]
}
}
// 这种
arrayUnique(array) {
if(array&&array.length)
return [...new Set(...array)];
}
}
统一风格,阅读代码就不会给人一种很凌乱的感觉。
统一自动格式化,遇到最坑的事,你的IDE会自动格式化,而同事又没有,或不按eslint来格,最后一提交全是冲突这种就没法进行下去了。人多的团队建议直接把eslint+githooks,不符合规范的代码直接不让提交。
附上几个大厂的前端规范
代码千万行,安全第一行;前端不规范,同事两行泪。
腾讯
tgideas.qq.com/doc/index.h…

京东
guide.aotu.io/index.html

百度
里面写了HTML、CSS、JavaScript的一些规范,有需要可以参考一下,给自己的团队定一份规范
命名
JavaScript
常规的命名规范有匈牙利命名法、驼峰式命名法、帕斯卡命名法
==匈牙利命名法==:变量名 = 类型 + 对象描述
- array 数组 a
- boolean 布尔值 b
- float 浮点数 l
- function 函数 fn
- int 整型 i
- object 对象 o
- regular 正则 r
- string 字符串 s
// 列表数据
let aListData = []
// 产品数据
let oProduct = {}
==驼峰式命名法==:变量名或函数名是由一个或多个单词连结在一起,其中第一个单词以小写字母开始,后面的所有单词的首字母都采用大写字母,这样的变量名看上去就像骆驼峰一样此起彼伏
const myName = 'haha'
const arrayUnique = (array) => {}
==帕斯卡命名法==:和驼峰式命名法类似,只不过第一个单词的首字母需要大写
const MyName = 'haha'
const ArrayUnique = (array) => {}
css
命名,100个人有100种命名,比如css,有用中划线-,下划线_,双下滑线的__,10个人写一个项目,css各种命名简直要不忍直视了,这算不算有强迫症。
常用的命名,像头部这种,命名就是header,像这种布局,我会来这样命名
<div class="header">
<div class="h-left">
<div class="h-l-back">返回</div>
<div class="h-l-number">12</div>
</div>
<div class="h-center">标题</div>
<div class="h-right">
<div class="h-r-shopping">图标</div>
</div>
</div>
.header{}
.h-left{}
.h-l-back{}
取父级元素第一个字母+当前内容,组成calss名,而取父级不超过三层,比如这样
<div class="main">
<div class="m-left">
<div class="m-l-nav">
<ul class="l-n-list">
<li class="n-l-item"></li>
</ul>
</div>
</div>
<div class="m-right"></div>
</div>
这种命名方式,让css名不容易起冲突,而每个人的命名风格都不一样,比如按 BEM 命名规范。
什么是 BEM 命名规范,Bem是块(block)、元素(element)、修饰符(modifier)的简写,由 Yandex 团队提出的一种前端 CSS 命名方法论。
注释
合理的注释,为什么要说合理的注释,有幸看到一个代码,200行的代码100行注释,好奇是写代码还是写文章的???注释应该帮助我们理解函数的目的,让我们不需要去看这个函数的具体逻辑和代码就可以快速的使用它。
能代码自解释,尽量不要写注释
// 获取产品数据缓存,用于当前页面渲染
Storge.get('productData')
// 设置产品列表数据,跳转到产品列表页需要用
Storge.get('productListData', productListData)
// 删除当前登录数据,清空退出
Storge.remove('loginState')
/**
* 判断 两个值 是否相等 **注意: **这个方法支持比较 arrays, array buffers, booleans, date objects, error objects, maps,
* numbers, Object objects, regexes, sets, strings, symbols, 以及 typed arrays. Object 对象值比较自身的属性,
* 不包括继承的和可枚举的属性。 不支持函数和DOM节点比较。
* @param value
* @param other
*/
static isEqual(value, other) {
return isEqual(value, other)
}
一些难解释的代码,还是要写上注释,不然可能过一段时间回来,你自己都看不懂了
/**
* @name path 路径必须是iconUrlPrefix + 年份(2020)+ 时间搓 + 后缀名组成(不按这个规则组成,请求失败)
*/
var suffix = imageUrl.split('.');
var type = suffix ? suffix[suffix.length - 1] : '';
var list = [{
token: res.token,
key: res.key,
path: "/" + res.iconUrlPrefix + new Date().toLocaleDateString().split("/")[0] + '/' + new Date().getTime() + '' + '.' + type,
provider: 'FASTDFS',
}]
最后总结一下,就是能代码自解释的,尽量通过上下文,函数命名,变量命名来解释代码的意图,逻辑复杂在通过注释来解释 ==命名的重要性要强于去写注释==
上面规范统一,按同一种格式命名,就剩下如何书写简洁,阅读性好,质量高的的代码了
提升代码的质量
函数SRP(功能单一)
==场景==:点击加入购物车,没登录需要跳到登录去,登录则添加到购物车
// 是否登录状态
export async function isLogin () {
const token = Storage.get('token')
const v = token.match(/##.+(##)?/g)[0];
if (v.startsWith('##ANONYMOUS')) {
return Promise.resolve(true)
}
return Promise.reject(new Error('当前状态未登录'))
}
// 添加到购物车
function addCart() {
isLogin().then(() => {
// 添加购物车逻辑操作
....
})
}
此时又有个需求,需要拿当前用户会员等级,一般上面已经有判断当前用户身份的代码,加个传参,改装一下
/**
*
* @export
* @param {*} isStatus 是否为返回身份状态(true为返回)(false)不返回
* @returns
*/
export async function isLogin (isStatus) {
const token = Storage.get('token')
const v = token.match(/##.+(##)?/g)[0];
if(isStatus){
if (v.startsWith('##ANONYMOUS')) {
return Promise.resolve('VIP0')
}
if (v.startsWith('##VIP1')) {
return Promise.resolve('VIP1')
}
if (v.startsWith('##VIP2')) {
return Promise.resolve('VIP2')
}
} else {
if (v.startsWith('##ANONYMOUS')) {
return Promise.reject(new Error('当前状态未登录'))
}
return Promise.resolve(true)
}
}
// 获取当前用户等级
const level = await isLogin(true)
此时应该遵循单一原则,不要把多个功能混在一个函数里面,不然后期此函数只会越来越大,越来越臃肿,命名已经没法很好的解释这个函数功能了
// 获取当前用户等级
export function getLevel() {
const token = Storage.get('token')
const v = token.match(/##.+(##)?/g)[0];
if (v.startsWith('##VIP1')) {
return 'VIP1'
}
if (v.startsWith('##VIP2')) {
return 'VIP2'
}
return 'VIP0'
}
// 获取当前用户等级
const level = getLevel()
让函数始终只用做一件事情,一个功能,不必考虑一个函数有多少个功能。
字典
==场景==:接口返回数据类型为integer、decimal、string、date、dateTime,我们需要显示为整数、小数、字符串、日期、日期和时间,拿起键盘马上就敲
let typeStatus = ''
switch (type) {
case 'integer':
typeStatus = '整数'
break;
case 'decimal':
typeStatus = '小数'
break;
case 'string':
typeStatus = '字符串'
break;
case 'date':
typeStatus = '日期'
break;
case 'dateTime':
typeStatus = '日期和时间'
break;
default:
typeStatus = ''
}
此时,用上字典,让代码优雅起来,写的不这么冗余
const typeDictionary = {
'integer': '整数',
'decimal': '小数',
'string': '字符串',
'date': '日期',
'dateTime': '日期和时间'
}
let typeStatus = typeDictionary[type] || '';
代码看起来,会不会显的整洁,明了呢。
主动中止
==场景==:验证表单,用户名和密码是否填写
formSubmit(data) {
if (!data.name) {
Toast('请填写姓名')
} else if (!data.password) {
Toast('请填写密码')
} else {
// 表单提交逻辑
...
}
}
以上写法也没有问题,但是一层层的ifelse看上去,让逻辑显的不是非常的清晰,业务的核心是在最底下,我们优化一下,让代码质量好一点
formSubmit(data) {
if (!data.name) {
Toast('请填写姓名')
return
}
if (!data.password) {
Toast('请填写密码')
return
}
// 表单提交逻辑
...
}
这种写法,不管是中间需要在加条件判断还是可读性来说,都比上面一层层的ifelse要好很多。
使用默认值
createADirectory(name) {
const breweryName = name || 'directoryName';
// ...
}
解构赋值,可读性一目了然
createADirectory(name = 'directoryName') {
// ...
}
传参控制
==场景==:封装一个ajax函数
function request(url, type, data, header) {
const sType = type || 'get';
const oData = data || {};
const oheader = type || {
'Content-Type': 'application/json;charset=utf8'
};
// 执行封装axios请求操作
...
}
函数参数应该控制在2个以内,如果参数超过两个,使用解构语法,不用考虑参数的顺序,这样可读性还是性能方面都比上面写法要好
function request({
url = '',
type = 'get',
data = {},
header = {
'Content-Type': 'application/json;charset=utf8'
}
} = {}) {
// 执行封装axios请求操作
...
}
至于类似应该使用let还是const 归纳一下
- 可读性
- 一致性
- 可扩性
写完自省,可能因为时间因素或赶进度原因,写出的代码功能是没问题了,回头代码质量臃肿不堪,不忍直视,后面需要改进,这样编程之路,就一是优化的过程中,习惯就越来越好了。