我发现前端同学中,对软件工程领域的巨著《代码整洁之道》讨论的甚少,团队中甚至还有一些多年的前端根本不知道这本书。 可能本身前端的东西太多了,已经学不过来了,再加上JS本身的灵活性,导致大家对代码整洁似乎没那么看重。看重的人,也往往缺乏实践或者不知道如何去实践。 本文总结了一些自己的经验,也总结了一些博客,汇总一篇JS/TS 代码指南。如有兴趣,还可以参考我的另一篇博文:SOLID原则与实践 - 掘金 (juejin.cn)
变量名
-
团队内部可以自己定义,合适的变量名应该能让人看出来这是什么东西,便于理解和维护. 例子:
currentDate 好过 time tmp 好过 s/a/b这种无意义的命名 常量使用全大写
-
保持命名的一致性 例如,用户相关的,大家都用user开头,比如userInfo,userName等
-
不要使用魔法数字 使用常量代替魔法数字
-
不用过多的使用上下文 比如
class User{ name:string }
好过
class User{ userName:string }
-
减少无用变量
比如return createUser(); const user = createUer(); return user;
函数
- 合适的函数名
和变量名一样,函数名需要能够直观的解释这个函数的作用。比如:getCurrentDay
我们还可以使用固定的前缀,比如:
- 发送服务请求相关的可以用requestXXX命名 ,
- 像服务器提交数据可以用submitXXX命名,
- 无参数但是有返回值的函数可以用getXXX命名,
- 创建了一个新对象的函数可以用createXX命名,
- 有参数但是无返回值的函数可以用handlerXXX命名,
- 有参数且有返回值的函数可以用processXXX命名,
- 返回值是布尔值的函数可以用isXXX/hasXXX命名,
- 如果对入参的对象有更改,可以使用 updateXXX,deleteXXX等命名。
- 合适参数默认值
function createUser(name = "nobody") {
// ...
}
3.参数不要太多,否则可以考虑拆分函数,或者封装参数。 比如
function createUser(name = "nobody",age='18',sex='man',licenceId='') {
// ...
}
可以封装为
function createUser({name = "nobody",age='18',sex='man',licenceId=''}) {
// ...
}
createUser({
name = "congbai",
age='28',
sex='man',
licenceId=''
})
或者将其拆分为
const user = createUserByName('congbai')
user.setAge(20)
user.setSex('man')
-
单一职责 老生长谈了,可参考SOLID原则与实践 - 掘金 (juejin.cn) 该处的难点在于,如何定义‘职责’。比如我们可以把'创建用户'作为一个职责,也可以将其细分为'创建用户名,设置用户年龄,设置用户性别'三个职责。这个要根据自己的业务场景去区分。 6个参考标准:
-
如果一个职责里面的代码超过50行,那肯定能再拆出来一些职责。
-
如果一段逻辑被两次以上重用,可以拆出来公用
-
如果一段逻辑没有副作用,可以拆出来
-
if 的判断条件如果过多,可以拆分出来
-
if/else内部的逻辑,尽量拆分出来
-
数组里面的map,reduce,foreach传入的代码片段,可以拆分出来
-
多层嵌套一定拆出来,最多两层
-
传入的参数如果在函数内被直接当做if的条件使用,那么这个if相关的逻辑应该在该函数之外处理: 例如:
function createUser(sex='man'){ if(sex==='man') { return createMan() } else{ return createWoman() } } functin getUser(){ const sex= getSex(); return createUser(sex); }
可以修改为
functin getUser(){ const sex= getSex(); if(sex ==='man'){ return createMan() }esle{ return createWoman() } }
-
善用es6的解构语法进行复制和赋值
比如user={ ...anotherUser, age:28 } allUser=[...oldUser,...newUser]
-
减少函数的副作用
- 避免修改参数以外的任何变量
- 如有可能,尽量返回一个新的对象,而不是对参数中的对象进行修改。 比如
function addUserToList(user,list){ user.age=19; list.push(user); } 可以替换成 function addUserToList(user,list){ return [...list,{...user,age:19}] }
之所以说有可能,是因为这种方式会带来性能的损耗,因此要衡量使用。
-
尽量使用函数式编程 比如数组中的foreach,filter等等。
-
使用多态和设计模式来减少if/else的判断,降低耦合性。 还是参见SOLID原则与实践 - 掘金 (juejin.cn)
-
使用Promise代替回调函数
类设计
-
尽量使用get set访问器对属性进行修改
-
多用组合,少用继承
-
如非必要,不要修改原型
-
set访问器可以返回'this',以便进行链式调用 比如
class User {
setName(name){ this.name = name; return this; } setAge(age){ this.age = age return this; }
} user.setName('葱小白').setAge(28)
-
类中方法的顺序最好按一定的顺序排列。比如在A中调用了B,那么B应该位于A之后,便于阅读。
其他
-
这些原则是参考的依据,不是需要严格遵守的。
-
没有一次性就能写的漂亮的代码,需要定期的按照这些原则进行修正
-
缩进,命名,短代码是代码像诗一样漂亮的保证
-
合理的命名能有效降低注释的必要性,但是该注释的地方还是要注释。当code review时,别人看不懂的地方,都应该有注释。