一些重构的建议:
- 提炼函数
* 避免出现超大函数
* 独立出来的函数有助于代码复用
* 独立出来的函数更容易被覆写
* 独立出来的函数如果拥有一个良好的命名,
* 它本身就起到了注释的作用。
比如在一个负责取得用户信息的函数里面,我们还需要打印跟用户信息有关的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();