JS重构之道

代码重构是成为一个优秀程序员的必经之路,在看多了糟心的代码后我们才能知道怎么写出不糟心的代码。同时重构代码锻炼了我们的耐心,细心,和勇气。又能加快项目的后期迭代速度,和代码的可维护性。简直是一件有百利而无一害的事情。

要说害处,还真有一件,那就是会产生bug(不过我们就是写bug的啊),尤其是对之前的业务代码一无所知的情况下。

1. 为什么要重构代码:

每个人在开发一个新项目时肯定都会思考如何设计,然后再进行编码。但是随着时间的流逝,功能的迭代。不同的人都会对之前的代码进行修改。于是最开始完美的设计结构逐渐衰弱,代码质量也慢慢沉沦,编码工作也从严谨的工程堕落为胡侃乱劈的随性行为。到了这种地步,就是时候来一次重构了。
套用一句名言:优秀的代码总是相似的,糟糕的代码却有各种各样的糟糕。主要体现在:

  1. 代码逻辑结构混乱:这其中包含的异常情况太多了,是代码重构中最糟糕的吧,勉强维持运行,但是没人敢改动,一动必出bug。
  2. 单文件或者单个函数代码行数过多:如果一个文件中代码上千行,在这个文件中极有可能还存在着其他糟糕的情况,增加功能,修改bug恨不得换一个高两米的显示器。不然鼠标滚轮的寿命就要减少好多年。
  3. 模块之间耦合性过高:这种情况下,全局变量一般会被较多使用。导致各模块互相牵制,改动困难。

2. 重构前:梳理代码

知己知彼,方能百战百胜(可能用在此处不恰当)。代码重构并不是说都能成功,没有良好的准备,很可能导致重构的最终失败。

想要顺利的对项目进行重构,第一步肯定是要了解这个项目。首先可以从代码的总体架构上着手,从全局把控原有的代码的糟心情况,初步评估代码的优化难度,以及我们重构要完成的目标。当然要结合项目的进度情况作出合理的排期。必经产品们关心的是上线时间,而不是代码质量。然后就可以深入阅读代码了。这是一个恶心的过程,耐心就是在这个时候锻炼的。不要走马观花式的读。最好做一下笔记。对原有代码逻辑做一下梳理。形成文档或者是脑图。这为下一步的重构打下坚实的基础,避免产生阻塞性的bug。这个过程可能不是读一遍代码就可以完成的,要多读几遍哦。这真的是一个很重要的过程,不骗你们。最后,为了避免个人的理解误差,要找几个人共同验证你梳理后的内容。拿着你梳理完的文档,对一些重要业务逻辑咨询产品,测试,后端等相关人员,请他们确认你的重构逻辑是没有问题的。这样你才能安心下手,以免后顾之忧。

在重构之前另一个重要的工作就是准备一份测试用例。如果能找到项目的需求文档,对我们的重构能起到事半功倍的效果。如果没有,那我们最好结合页面功能,自己写一份测试用例,为我们重构后的结果评估提供标准。测试工作在重构过程中的作用是如何强调都不为过的。因为即使我们的准备很充分,可以避免引入绝大多数bug,但是我们毕竟是专职写bug的程序员。不能因为重构,而让原先使用起来正常的功能挂掉。这就会给那些反对重构的人一个津津乐道的把柄。

3. 重构中:胆大心细

好的开始是成功的一半。有了前面一步完美的准备,我们就可以开动了。

针对不同情况的源代码,重构的策略也会不同。但是时刻不要忘记我们的初心-重构代码。

在自主可控的情况下,不要对之前的代码结构畏首畏尾。这也不敢动,那也不敢动,我们的重构有什么意义呢。所以重构是需要一定勇气的,不能因为过多的顾虑而放弃改动。

对改动过的代码、功能,不能想当然,认为一定完美,没有bug。重构的最基本要求就是:小步前进、频繁测试。保证重构后的代码不引入新的bug。

下面介绍几个在重构中经常使用到的几个技巧:

  1. 重新组织函数:
    函数可以说是程序的细胞。一个程序肯定是有很多函数组合而成。函数的混乱必然导致程序难以维护和迭代。重构的大部分时间都是在对函数进行整理。
    首先是拆分过长的函数,每个人修改这种函数都会无比痛苦。函数中包含各种数据信息,这些信息又被错综复杂的功能逻辑掩盖,不易鉴别。秉着一个函数只做一件事的原则,可以将这种函数拆分成多个独立的、命名良好的小函数。
    另一个问题就是函数中的变量,这包括参数、局部变量、全局变量。函数要想保持独立性和良好的复用性,就不应该直接依赖全局变量,而是应该以参数的形式传入。既然是全局变量,肯定不是一个函数使用,这会导致各函数之间紧密耦合,维护困难。重构过程中要尽量减少全局变量。局部变量是函数重构的一个困难源泉,它会驱使你无意识中写出很长的函数,而且使得代码很难被提炼。所以应该尽可能的把局部变量替换为一个查询函数。参数传入函数后就会变成局部变量,所以要减少参数的数量,只传必要的参数。如果参数过多,可以使用对象结构替换。
// 只传必要的参数
function column(width,height,square){
    console.log("矩形的宽度为"+width);
    console.log("矩形的高度为"+height);
    console.log("矩形的面积为"+square);
}

// square可以由width和height计算得到
function column(width,height){
    var square = width*height;
    console.log("矩形的宽度为"+width);
    console.log("矩形的高度为"+height);
    console.log("矩形的面积为"+square);
}
  1. 简化条件表达式
    复杂的条件逻辑是最常见的导致程序难以阅读和维护原因之一。每一个条件分支都需要编码做不同的事,随着分支的增加,很快函数也会变得庞大起来。大型函数本身就难以阅读,而条件分支更是加大了阅读难度。
    你可以将每个分支中执行的代码分解为多个独立的函数,根据每个函数的作用,合理命名。然后将原函数中的代码该外函数调用。这样不仅可以更清楚的表达自己的意图,而且可以突出条件逻辑,更清楚的表明每个分支的作用和原因。
    避免出现嵌套条件表达式。在可能的情况下,替换条件表达式。
// 使用命令模式,替换条件表达式
function(flag){
    if(flag==="left"){
        move("right");
    }else if(flag==="right"){
        move("left");
    }else if(flag==="top"){
        move("bottom");
    }else if(flag==="bottom"){
        move("top");
    }
}
// 替换条件表达式
function moveTo(flag){
    command.flag;
}
var command = (function(){
    var left = function(){
        move("right");
    }
    var right = function(){
        move("left");
    }
    var top = function(){
        move("bottom");
    }
    var bottom = function(){
        move("top");
    }
    return {
        left,right,top,bottom
    }
})();
function getPayAmount() {
    let result;
  if(isDead) {
    result = deadAmount();
  } else {
    if(isSeparated) {
        result = separatedAmount();
    } else {
        if(isRetired) {
        result = retiredAmount();
      } else {
        result = normalPayAmount();
      }
    }
  } 
  return result;
}

//提前return,简化分支嵌套逻辑

function getPayAmount(){
  if(isDead) return deadAmount();
  if(isSeparated) return separatedAmount();
  if(isRetired) return retiredAmount();
  return normalPayAmount();
}

技巧,示例展示的有限,有兴趣进一步了解的同学可以阅读《重构--改善既有代码的设计》。书中详细介绍了重构代码的各种技巧以及示例。

重构更重要的是一种思想,是对代码易阅读,易维护的一种追求。他应该像水和空气一样融入我们的编码过程中,随时随地的重构。关于重构技巧,就是我们编码过程的养成的良好习惯和设计模式的灵活运用。当我们知道哪些编码是有问题的,我们必定回去寻找改变这个问题的方法。就是在这种不断发现问题,解决问题的过程中,提升自我,实现我们的优雅编码的理想。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,114评论 0 13
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,463评论 25 707
  • 省察日记 昨天店里开始搬家,这两天下来,身体都像快要散架一样疲惫不堪。 觉察两天里的起心动念,检视到情绪很不稳定。...
    正娟_d019阅读 204评论 2 1