以下都是一些建議,沒有哪些是必須嚴(yán)格遵守的標(biāo)準(zhǔn)瓣铣。
具體是否需要重構(gòu)答朋,以及如何進(jìn)行重構(gòu),這需要我們根據(jù)系統(tǒng)的類型坯沪、項(xiàng)目工期绿映、人力等外界因素一起決定。
22.1 提煉函數(shù)
避免出現(xiàn)過長的函數(shù),函數(shù)體內(nèi)的邏輯應(yīng)該清晰明了叉弦。
比如:
var getUserInfo = function(){
ajax('http://xxxx', function( data ){
console.log( 'userId:' + data.userId);
console.log( 'userName:' + data.userName:);
console.log( 'nickName' + data.nickName)
})
}
可以重構(gòu)為:
var printDetails = function( data ){
console.log( 'userId:' + data.userId);
console.log( 'userName:' + data.userName:);
console.log( 'nickName' + data.nickName);
}
var getUserInfo = function(){
ajax('http://xxxx', function( data ){
printDetails( data )
})
}
22.2 合并重復(fù)的條件片段
如果一個(gè)函數(shù)體內(nèi)有一些條件分支語句丐一,而這些條件分支語句內(nèi)部散步了一些重復(fù)的代碼,那么就有必要進(jìn)行合并去重工作淹冰。
var padding = function( currPage ) {
if( currPage <= 0 ){
currPage = 0;
jump( currPage ); //跳轉(zhuǎn)
} else if ( currPage >= totalPage ){
currPage = totalPage;
jump( currPage ); //跳轉(zhuǎn)
} else {
jump( currPage ); //跳轉(zhuǎn)
}
}
以上代碼進(jìn)行重構(gòu)后:
var padding = function( currPage ) {
if( currPage <= 0 ){
currPage = 0;
} else if ( currPage >= totalPage ){
currPage = totalPage;
}
jump( currPage ); //跳轉(zhuǎn)库车,將jump函數(shù)獨(dú)立出來
}
22.3 把條件分支語句提煉成函數(shù)
在程序設(shè)計(jì)中,復(fù)雜的條件分支語句是導(dǎo)致程序難以閱讀和理解的重要原因樱拴,而且容易導(dǎo)致一個(gè)龐大的函數(shù)柠衍。
將條件分支語句提煉為一個(gè)單獨(dú)函數(shù),是一個(gè)很好的方法晶乔。
以下代碼:
var getPrice = function( price ){
var data = new Date();
if ( data.getMonth() >= 6 && data.getMonth() <= 9 ) { //夏天
return price * 0.8;
}
return price
}
可重構(gòu)為:
var isSummer = function() {
var data = new Date();
return data.getMonth() >= 6 && data.getMonth() <= 9;
}
var getPrice = function( price ){
if ( isSummer() ) { //夏天
return price * 0.8;
}
return price
}
22.4 合理使用循環(huán)
在函數(shù)體內(nèi)珍坊,如果有些代碼實(shí)際上負(fù)責(zé)的是一些重復(fù)性的工作,那么合理利用循環(huán)不僅可以完成同樣的功能正罢,還可以使代碼量更少阵漏。
下面這個(gè)重構(gòu)代碼真好,推薦大家學(xué)習(xí):
原代碼:
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()
重構(gòu)之后:
var createXHR = function(){
var versions = ['MSXML2.XMLHttp.6.0','MSXML2.XMLHttp.3.0','MSXML2.XMLHttp'];
for(var i = 0, len = versions.length; i < len;i++ ){
try{
return new ActiveXObject(version)
} catch (e){
}
}
}
var xhr = createXHR()
精彩之處在于很好的運(yùn)用for循環(huán)處理了代碼重復(fù)的問題翻具。
22.5 提前讓函數(shù)退出代替嵌套條件分支
摒棄函數(shù)只有一個(gè)出口的想法履怯,盡量減少if else語句嵌套,如果滿足條件不想再繼續(xù)執(zhí)行裆泳,請(qǐng)直接 return 退出循環(huán)叹洲。
var del = function( obj ){
var ret;
if( !obj.isReadOnly ){ //不為只讀的才能被刪除
if ( obj.isFolder ) { //如果是文件件
ret = deleteFolder( obj )
} else if ( obj.isFile ) { //如果是文件
ret = deleteFile( obj )
}
}
return ret
}
上面這段代碼理解起來比較有難度,為了看到函數(shù)出口工禾,必須得讀完函數(shù)所有內(nèi)容运提,有時(shí)候,很多內(nèi)容是你不用也不想看到的帜篇。
重構(gòu)之后:
var del = function( obj ){
if ( obj.isReadOnly ){
return
}
if ( obj.isFolder ){
return deleteFolder( obj );
}
if ( obj.isFile ){
return deleteFile( obj );
}
}
看完感覺就兩個(gè)字:清爽糙捺!
22.6 傳遞對(duì)象參數(shù)代替過長的參數(shù)列表
避免為函數(shù)傳遞過多的參數(shù),參數(shù)越多笙隙,函數(shù)就越難理解和使用洪灯。搞反參數(shù)位置也會(huì)出錯(cuò)。
最好的傳遞方式竟痰,就是把參數(shù)放進(jìn)一個(gè)對(duì)象內(nèi)签钩,然后把該對(duì)象傳遞給函數(shù)。
var obj = {
id: 123,
name: 'wang',
age: 20,
sex: '男'
}
var showInfo = function( obj ){
console.log(obj.id);
console.log(obj.name);
console.log(obj.age);
console.log(obj.sex);
}
22.7 盡量減少參數(shù)數(shù)量
如果一個(gè)函數(shù)不需要傳入任何參數(shù)就可以使用坏快,這種函數(shù)是深受人們喜愛的铅檩。
比如,現(xiàn)在有一個(gè)畫圖函數(shù) draw 莽鸿,它現(xiàn)在只能繪制正方形昧旨,接收了三個(gè)參數(shù)拾给。分別是width,height兔沃,square
var draw = function( width, height, square ){}
但實(shí)際中蒋得,square是可以通過width和height算出來的。所以上面這段代碼可以變成:
var draw = function( width, height ){
var square = width * height;
}
所以乒疏,請(qǐng)盡量較少函數(shù)的參數(shù)额衙。
22.8 少用三目運(yùn)算符
如果條件分支邏輯簡單清晰,可以使用三目運(yùn)算符怕吴,但是如果分支邏輯非常復(fù)雜窍侧,最好不要使用三目運(yùn)算符。
三目運(yùn)算符和if else 性能一樣转绷,可是在處理復(fù)雜邏輯時(shí)候伟件,三目運(yùn)算符會(huì)損失代碼可讀性和可維護(hù)性。
22.9 合理使用鏈?zhǔn)秸{(diào)用
var user = {
id: null,
name: null,
setId: function( id ) {
this.id = id;
return this;
},
setName: function( name ){
this.name = name;
return this;
}
}
user.setId( 1314 ).setName( 'sven' );
22.10 分解大型類
var Spirit = function( name ){
this.name = name;
}
Spirit.prototype.attack = function( type ) {
if( type == 'waveBoxing' ){
console.log( this.name + ':使用波動(dòng)拳');
} else if ( type == 'whirlKick' ){
console.log( this.name + ':使用旋風(fēng)腿');
}
}
var spirit = new Spirit('RYU');
spirit.attack('waveBoxing');
spirit.attack('whirlKick');
在以上代碼中暇咆,我們可以看到 Spirit.prototype.attack 這個(gè)方法太過于龐大锋爪,實(shí)際上,它完全有必要作為一個(gè)單獨(dú)的類存在爸业。
面向?qū)ο笤O(shè)計(jì)鼓勵(lì)將行為分布在合理數(shù)量的更小對(duì)象之中。
重構(gòu)之后:
var Attack = function( spirit ){
this.spirit = spirit;
}
Attack.prototype.start = function( type ){
return this.list[type].call(this);
}
Attack.prototype.list = {
waveBoxing: function(){
console.log( this.spirit.name + ':使用波動(dòng)拳');
},
whirlKick: function(){
console.log( this.spirit.name + ':使用旋風(fēng)腿');
}
}
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( 'RYU' );
spirit.attack( 'waveBoxing' );
spirit.attack( 'whirlKick' );
現(xiàn)在的Spirit精簡了很多亏镰,不再包括各種攻擊方法扯旷,而是把攻擊動(dòng)作委托給Attack類的對(duì)象來執(zhí)行。
22.11 用return退出多重循環(huán)
var func = function() {
for( var i = 0; i < 10; i++){
for( var j = 0; j < 10; j++ ){
if( i * j > 30 ){
return;
}
}
}
console.log( i )
}
func();
以上代碼在return退出整個(gè)方法之后索抓,會(huì)導(dǎo)致 console.log(i) 沒機(jī)會(huì)執(zhí)行钧忽。
解決方案:
如果return 之后代碼比較少,可以:
var func = function() {
for( var i = 0; i < 10; i++){
for( var j = 0; j < 10; j++ ){
if( i * j > 30 ){
return i;
}
}
}
}
console.log(func())
如果代碼比較多逼肯,就可以:
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();