记录平时JS代码重构的经验,React代码重构也是基于JS重构
1、提炼函数
坏味道:函数过长,不得不加上很多注释。
我们要做的就是独立函数,函数体内逻辑应该清晰明了。好处是:
- 避免出现超大函数,提高观赏性
- 独立函数有助于代码复用
- 更容易被覆写
示例:略
2、拆分判断条件
坏味道:复杂的条件分支语句,导致程序难以阅读和理解。
let getPrice = function(price){
let date = new Date();
//观察这段代码
if(date.getMouth() >= 6 && date.getMouth() <= 9){
return price * 0.8;
}
return price;
}
解析:代码表达的意思 和代码自身还存在一些距离,阅读人员必须要花一些精力才能证明它传达的意图。如果条件再长些,更难理解。
if(date.getMouth() >= 6 && date.getMouth() <= 9){
return price * 0.8;
}
理想状态:单独提炼函数,函数命名语义化!既能准确表达代码的意思,本身又能起到注释的作用。
let isSummer = function(){
let date = new Date()
return date.getMouth() >= 6 && date.getMouth() <= 9
}
let getPrice = function(price){
if(isSummer()){
return price * 0.8;
}
return price;
}
3、提前退出 代替 嵌套If
坏味道:嵌套的条件分支绝对是代码维护者的噩梦
let del = function(obj){
let ret;
if(!obj.isReadOnly){
if(obj.isFolder){ //如果是文件夹
ret = deleteFolder(obj;)
}else if(obj.isFile){ //如果是文件
ret = deleteFile(obj);
}
}
return ret;
}
解析: 实际上,如果对函数的其他部分不感兴趣,那就应该立即退出。引导读者去看一些没有用的else片段,只会妨碍他们对程序的理解。
改造之后~
let del = function(obj){
if(obj.isReadOnly) return; //反转if表达式
if(obj.isFolder){
return deleteFolder(obj);
}
if(obj.isFile){
return deleteFile(obj);
}
}
这样是不是好多了😋
4、传递参数不要长,标记不要做参数
坏味道:函数可能接受多个参数,参数数量越多,函数越难以理解。使用者需要搞明白全部参数的含义。
优化措施
- 可以用对象代替多参数
//bad
function show(id,name,address,sex,mobile){
//TODO
}
//good
function show(person){
//TODO person = {id,name,address,sex,mobile}
}
- 优化函数逻辑 ,控制在 3个参数以内最佳。
function show(arg1,arg2,arg3){}
这条不记得是哪位大神说的,不过根据个人经验来说,蛮有用的~
- boolean类型的标记 不要做参数。
标记告诉你的用户这个函数做的事情不止一件。但是函数应该只做一件事。如果你的函数中会根据某个布尔参数产生不同的分支,那就拆分这个函数。
//标记告诉你的用户这个函数做的事情不止一件。但是函数应该只做一件事。如果你的函数中会根据某个布尔参数产生不同的分支,那就拆分这个函数。
// Bad
function createFile(fs,name, temp) {
if(temp) {
fs.create("./temp/"+ name);
} else{
fs.create(name);
}
}
// Good 这里函数写的比较短,实际函数是很长的,性价比高。
function createTempFile(fs,name) {
fs.create("./temp/"+ name);
}
function createFile(name) {
fs.create(name);
}
const getFile = temp ? createTempFile(fs,name) : fs.create(name);
5、合理使用三目
坏味道:有些程序员喜欢大规模使用三目运算符。直白的说,过分嵌套三目,其损失的可读性和可维护性,相对于节约的代码量来说,因小失大。
例如:
// 逻辑简单可用三目
let global = typeof window != 'undefined' ? window : this;
// 复杂逻辑,使用三目 bad!!!
if(!aup || !bup){
return a === doc ? -1 :
b === doc ? 1 : aup ? -1; bup ? 1 : sortInput ? true : 0;
}
6、巧用return 推出函数
其实之前已经用到过return了,这里再单独说下
坏味道:假如函数体中有一个两重循环语句,我们需要在内层循环中判断,当达到某个临界条件时,退出外层的循环。 于是出现了 引入控制变量这个操作:
let func = function(){
outerloop;
for(var i = 0; i< 10; i++){
innerloop;
for(var j = 0;j< 10;j++){
if(i * j > 30){
break outerloop
}
}
}
}
更简单的做法是,在需要终止循环的时候直接退出整个方法
let func = function(){
for(var i = 0; i< 10; i++){
for(var j = 0;j< 10;j++){
if(i * j > 30){
return print('执行完成,退出' + i * j);
}
}
}
}
7、善用符号常量
坏味道:代码中莫名其妙的数字,着实让人摸不着头脑。
if(temperature > 32){ //此处的32 并不知道要表达什么?
//TODO...
}
解析:利用符号常量 + 注释的方式,使代码一目了然。TS中符号常量可进而抽取为 枚举TypeScript
/** 临界温度 */
const FREEZING = 32;
...
if(temperature > FREEZING_POINT){
//TODO...
}
8、避免副作用
坏味道:理想情况下 ,一个函数,处理的数据来自于形参。如果一个函数中即引用了形参,又引入了全局变量。其已经具有了破坏性,会导致古怪的时序性耦合及顺序依赖。
例如:
let name = "Ryan McDermott";
function splitIntoFirstAndLastName() {
name = name.split(" ");
}
splitIntoFirstAndLastName();
console.log(name); // ["Ryan", "McDermott"];
// 如果另一个函数中使用了name,就有可能因为name是数组而不能正常运行。
我们来优化下
function splitIntoFirstAndLastName(name) {
return name.split(" "); //通过形参传入,避免了难以捕获的 依赖问题。
}
var name = "Ryan McDermott"
var newName = splitIntoFirstAndLastName(name);
console.log(name); // "Ryan McDermott";
console.log(newName); // ["Ryan", "McDermott"];
9、优化if
坏味道:if判断过多, 虽然能运行,但是很丑陋,怎么改善。
function excute(key){
if(key === "A" ){
return //something ...
}
if(key === "B"){
return //something1 ...
}
if(key === "C"){
return//something2 ...
}
if(key === "D){
return//something3 ...
}
}
优化之后
let func = {
"A":()=>{
//something ...
},
"B":()=>{
//something1 ...
},
"C":()=>{
//something2 ...
},
"D":()=>{
//something3 ...
}
}
let excute = key => func[key] && func[key]();
补充:
代码命名规范
CODELF
实际开发中,很多都不是自己写的代码。面对之前的屎山,我想应该在不影响既有功能的前提下,refactoring it!同时确保自己尽量不要写shi代码。即是技术,也是艺术。