第二十二章 代码重构

以下都是一些建议,没有哪些是必须严格遵守的标准。
具体是否需要重构,以及如何进行重构,这需要我们根据系统的类型、项目工期、人力等外界因素一起决定。

22.1 提炼函数

避免出现过长的函数,函数体内的逻辑应该清晰明了。

比如:

var getUserInfo = function(){
    ajax('http://xxxx', function( data ){
        console.log( 'userId:' + data.userId);
        console.log( 'userName:' + data.userName:);
        console.log( 'nickName' + data.nickName)
    }) 
}

可以重构为:

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 合并重复的条件片段

如果一个函数体内有一些条件分支语句,而这些条件分支语句内部散步了一些重复的代码,那么就有必要进行合并去重工作。

var padding = function( currPage ) {
    if( currPage <= 0 ){
        currPage = 0;
        jump( currPage );   //跳转
    } else if ( currPage >= totalPage ){
        currPage = totalPage;
        jump( currPage );   //跳转
    } else {
        jump( currPage );   //跳转              
    }
}

以上代码进行重构后:

var padding = function( currPage ) {
    if( currPage <= 0 ){
        currPage = 0;
    } else if ( currPage >= totalPage ){
        currPage = totalPage;
    } 
    jump( currPage );   //跳转,将jump函数独立出来
}

22.3 把条件分支语句提炼成函数

在程序设计中,复杂的条件分支语句是导致程序难以阅读和理解的重要原因,而且容易导致一个庞大的函数。
将条件分支语句提炼为一个单独函数,是一个很好的方法。

以下代码:

var getPrice = function( price ){
    var data = new Date();
    if ( data.getMonth() >= 6 && data.getMonth() <= 9 ) {  //夏天
        return price * 0.8;
    }
    return price
}

可重构为:

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 合理使用循环

在函数体内,如果有些代码实际上负责的是一些重复性的工作,那么合理利用循环不仅可以完成同样的功能,还可以使代码量更少。

下面这个重构代码真好,推荐大家学习:

原代码:

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, len = versions.length; i < len;i++ ){
       try{
          return new ActiveXObject(version) 
       } catch (e){

       }
  }
}

var xhr = createXHR() 

精彩之处在于很好的运用for循环处理了代码重复的问题。

22.5 提前让函数退出代替嵌套条件分支

摒弃函数只有一个出口的想法,尽量减少if else语句嵌套,如果满足条件不想再继续执行,请直接 return 退出循环。

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 );
  }
}

看完感觉就两个字:清爽!

22.6 传递对象参数代替过长的参数列表

避免为函数传递过多的参数,参数越多,函数就越难理解和使用。搞反参数位置也会出错。

最好的传递方式,就是把参数放进一个对象内,然后把该对象传递给函数。

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 尽量减少参数数量

如果一个函数不需要传入任何参数就可以使用,这种函数是深受人们喜爱的。

比如,现在有一个画图函数 draw ,它现在只能绘制正方形,接收了三个参数。分别是width,height,square

var draw = function( width, height, square ){}

但实际中,square是可以通过width和height算出来的。所以上面这段代码可以变成:

var draw = function( width, height ){
    var square = width * height;
}

所以,请尽量较少函数的参数。

22.8 少用三目运算符

如果条件分支逻辑简单清晰,可以使用三目运算符,但是如果分支逻辑非常复杂,最好不要使用三目运算符。

三目运算符和if else 性能一样,可是在处理复杂逻辑时候,三目运算符会损失代码可读性和可维护性。

22.9 合理使用链式调用

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 + ':使用波动拳');
    } else if ( type == 'whirlKick' ){
        console.log( this.name + ':使用旋风腿');
    }
}

var spirit = new Spirit('RYU');

spirit.attack('waveBoxing');
spirit.attack('whirlKick');

在以上代码中,我们可以看到 Spirit.prototype.attack 这个方法太过于庞大,实际上,它完全有必要作为一个单独的类存在。

面向对象设计鼓励将行为分布在合理数量的更小对象之中。

重构之后:

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 + ':使用波动拳');
  },
  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( 'RYU' );

spirit.attack( 'waveBoxing' );
spirit.attack( 'whirlKick' );

现在的Spirit精简了很多,不再包括各种攻击方法,而是把攻击动作委托给Attack类的对象来执行。

22.11 用return退出多重循环

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退出整个方法之后,会导致 console.log(i) 没机会执行。

解决方案:
如果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();
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,955评论 18 399
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 13,146评论 1 51
  • 说到茶道,我是个地地道道的门外汉,也是在红菇的影响下,第一次接触了茶文化,第一次了解了红茶的故事,感触颇深。 人们...
    林星儿阅读 3,034评论 0 4
  • 有的时候,你看一部电视剧或者电影,也许只为了看到那一句话而已罢了。关于电影里的剧情和人物你可能早已经忘记。但是那句...
    邓小怪阅读 3,214评论 0 0
  • 二十岁的你,能干什么?二十岁的你或许在上大学,每天睡觉学习玩手机?二十岁我们充满稚嫩但又初步接触到这个社会的烟尘之...
    柒89阅读 2,750评论 0 0