代码重构
原文链接 https://ronghuaxueleng.github.io/2016/10/12/JavaScript%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B8%8E%E5%BC%80%E5%8F%91%E5%AE%9E%E8%B7%B5-21%E4%BB%A3%E7%A0%81%E9%87%8D%E6%9E%84/
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。
一些重构的建议:
- 提炼函数
* 避免出现超大函数
* 独立出来的函数有助于代码复用
* 独立出来的函数更容易被覆写
* 独立出来的函数如果拥有一个良好的命名,
* 它本身就起到了注释的作用。
比如在一个负责取得用户信息的函数里面,我们还需要打印跟用户信息有关的log,那么打印log的语句就可以被封装在一个独立的函数里:
var getUserInfo = function() {
ajax('http://xxx.com/userInfo', function(data) {
console.log('userId: ' + data.userId);
console.log('userName: ' + data.userName);
console.log('nickName: ' + data.nickName);
});
};
可以改成:
var getUserInfo = function() {
ajax('http://xxx.com/userInfo', function(data) {
printDetails(data);
});
};
var printDetails = function(data) {
console.log('userId: ' + data.userId);
console.log('userName: ' + data.userName);
console.log('nickName: ' + data.nickName);
}
合并重复的条件片段
如果一个函数内有一些条件分支语句,而这些条件分支语句内部散步了一些重复的代码,那么就有必要进行合并去重工作。//页面跳转 var paging = function(currPage) { if (currPage <= 0) { currPage = 0; jump(currPage); //跳转 } else if (currPage >= totalPage) { currPage = totalPage; jump(currPage); //跳转 } else { jump(currPage); //跳转 } }
改成
//页面跳转
var paging = function(currPage) {
if (currPage <= 0) {
currPage = 0;
} else if (currPage >= totalPage) {
currPage = totalPage;
}
jump(currPage); //跳转
}
把条件分支语句提炼成函数
在程序设计中,复杂的条件分支语句是导致程序难以阅读和理解的重要原因,而且容易导致一个庞大的函数,所以通常我们要进行一定的提炼。//计算商品价格,如果处于夏季,全部商品八折出售 var getPrice = function(price) { var date = new Date(); if (date.getMonth() >= 6 && date.getMonth <= 9) { //夏季 return price * 0.8; } return price; }
改成
//计算商品价格,如果处于夏季,全部商品八折出售
var getPrice = function(price) {
if (isSummer()) { //夏季
return price * 0.8;
}
return price;
}
var isSummer = function() {
var date = new Date();
return date.getMonth() >= 6 && date.getMonth <= 9;
}
合理使用循环
var createXHR = function() { var xhr; try{ xhr = new ActiveXObject('MSXML2.XMLHttp.6.0'); } catch(e) { try { xhr = new ActiveXObject('MSXML2.XMLHttp.3.0'); } catch(e) { xhr = new ActiveXObject('MSXML2.XMLHttp'); } } return xhr; }; var xhr = createXHR();
改成:
var createXHR = function() {
var versions = ['MSXML2.XMLHttp.6.0', 'MSXML2.XMLHttp.3.0', 'MSXML2.XMLHttp'];
for (var i = 0, version; version = versions[i++]; ) {
try {
return new ActiveObject(version);
} catch(e) {
}
}
};
var xhr = createXHR();
提前让函数退出代替嵌套条件分支
var del = function(obj) { var ret; if (!obj.isReadOnly) { //不为只读的时候才可以删除 if (obj.isFolder) { //如果是文件夹 ret = deleteFolder(obj); } else if (obj.isFile) { //如果是文件 ret = deleteFile(obj); } } return ret; }
改成:
var del = function(obj) {
if (obj.isReadOnly) {
return;
}
if (obj.isFolder) { //如果是文件夹
return deleteFolder(obj);
}
if (obj.isFile) { //如果是文件
return deleteFile(obj);
}
}
传递对象参数代替过长的参数列表
有时候一个函数可能接收多个参数,而参数的数量越多函数就越难理解和使用。这时我们可以把参数放入一个对象内,然后把对象传入。var setUserInfo = function(id, name, address, sex, mobile, qq) { console.log('id=' + id); console.log('name=' + name); console.log('address=' + address); console.log('sex=' + sex); console.log('mobile=' + mobile); console.log('qq=' + qq); } setUserInfo(1234, cyseria, guangzhou, female, 188*, 52*);
改成:
var setUserInfo = function(obj) {
console.log('id=' + obj.id);
console.log('name=' + obj.name);
console.log('address=' + obj.address);
console.log('sex=' + obj.sex);
console.log('mobile=' + obj.mobile);
console.log('qq=' + obj.qq);
}
setUserInfo({
id: 1234,
name: cyseria,
address: guangzhou,
sex: female,
mobile: 188***,
qq: 52***
});
尽量减少参数数量
尽量减少一些没必要的不会使用或者可以求出的参数。这里不做过多阐述。少用三目运算
有时候我们用三目运算会觉得它性能高,代码量少。但是在实际开发中,即使把一段代码循环一百万次,使用三目运算和if,else
的时间开销依旧在同个级别中。同样,相比损失的代码可读性和可维护性,他能节省的代码量可以忽略不计。
至于例子,看看下面那个你就知道了:
if (!aup || bup) {
return a === doc ? -1 :
b === doc ? 1 :
aup ? -1 :
bup : -1 :
sortInput ? (indexOf.call(sortInput, a) - indexOf.call(sortInput, b)) :
0;
}
当然,如果只是简单的一句,用一下也没什么所谓。
合理使用链式调用
使用jq的对链式调用一定不陌生,在自己编写函数的时候也可以使用这点,返回自身。但是他也有一个坏处,调试的时候不方便。所以如果链条的结构稳定后期不易修改,那么使用他无可厚非,但是如果该链经常发生变化那么还是用普通的调用吧。var User = { id: null, name: null, setId: function(id) { this.id = id; return this; }, setName: function(name) { this.name= name; return this; } }; console.log(User.setId(1234).setName('cyseria'));
分解大型类
var Spirit = function(name) { this.name = name; }; Spirit.prototype.attack = function(type) { if (type === 'waveBoxing') { console.log(this.name + ':使用波动拳'); } else if (type === 'whirlKick') { console.log(this.name + ':使用旋风腿'); } }; var Spirit = new Spirit('AAA'); Spirit .attack('waveBoxing'); Spirit .attack('whirlKick');
改成:
var Attack = function(spirit) {
this.spirit = spirit;
};
Attack.prototype.start = function(type) {
return this.list[type].call(this);
}
Attack.prototype.list= function(type) {
waveBoxing: function() {
console.log(this.spirit.name + ':使用波动拳');
},
whirlKick: function() {
console.log(this.spirit.name + ':使用旋风腿');
}
};
var Spirit = function(name) {
this.name = name;
this.attackObj = new Attack(this);
};
Spirit.prototype.attack = function(type) {
this.attackObj.start(type);
};
var Spirit = new Spirit('AAA');
Spirit .attack('waveBoxing');
Spirit .attack('whirlKick');
用return退出多重循环
假设在函数体内有一个两重循环语句,我们需要在内层循环中判断当达到某个临界条件时退出外层循环。var print = function(i) { console.log(i); }; var func = function() { for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++) { if (i * j > 30) { return print(i); } } } }; func();