重构代码的Tricks

本文作者:ivweb villainthr

js的设计模式是针对于整体代码的设计是否合理,给出了一些具体的解决办法。 而重构代码就是依赖于设计模式而实现的一个必要手段,可以说设计模式就是重构代码的目标,但他的手段却不仅仅只有设计模式这些大而全的,同样存在小而精,我们随处可以使用的。

封装功能块代码

我们通常在写代码的时候,一开始,并不需要考虑太多。在后期可以进行修改和提炼。 比如,我有个业务需求,是创建一个div并且渲染数据到页面上,并且根据data的不同,改变div的状态.

function(data){
        var div = document.createElement("div"),
        div = data.name;
        document.body.append(div);
        if(data.isShow){
                div.style.display = "block";
        }else{
                div.style.display = "none";
        }
}

但事实上,这个函数里面还有一个代码块,就是根据data.isShow改变div的状态.我们可以对其进行封装。

function(data){
        var div = document.createElement("div"),
        div = data.name;
        document.body.append(div);
        changeState(data.isShow,div);
}
function changeState(flag,div){
        div.style.display = flag?"block":"none";
}

提取公因式

这里主要针对于,多次重复调用同一个封装代码块函数。

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

根据flag向反方向移动,可以看出,里面都有用到了move()这个方法,要知道,分支语句是最不利于程序阅读的,而且我们要尽可能的减少和简化分支语句里面的程序量,让阅读者耗费在分支语句上的时间降到最少。上面代码可以这样写。

function(flag){
        var dir;
        if(flag==="left"){
                dir = "right";
        }else if(flag==="right"){
                dir = "left";
        }else if(flag==="top"){
                dir = "bottom";
        }else if(flag==="bottom"){
                dir = "top";
        }
        move(dir);
}

恩,当然,这样写也是违反人性的。我们可以使用命令模式进行重构。 这就涉及到另外一个tip.

将分支转化为函数

上面代码里面的分支完全可以使用函数来进行代替。

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

这样,虽然增加了一个对象,但是代码确实清晰可见的。 这就是通过命令模式,来重构代码,完成性能和阅读的优化。 但有时候,使用分支,会比这样更简洁,那当然可以使用分支啦。 而使用分支还要主意一个tip就是.

不要过度嵌套

这里想说的就两点,一是,尽可能不使用分支,二是,如果嵌套分支,尽量改为不嵌套。 不使用分支的情况上面已经说了,如果使用分支,那么请不要嵌套,或者说不要过度嵌套。因为一个分支已经很难阅读了,md,你再加个嵌套,你还让不让人读了。 而解决过度嵌套的方法真的是千千万万,我这里就介绍一个比较简单的。使用return 提早退出嵌套。

function move(obj){
        if(obj.isShow){
                if(obj.isTop){
                        if(obj.isLeft){
                                return move("TopLeft");
                        }
                }else{
                        return false;
                }
        }else {
                return false;
        }
}

这,看着爽不爽。 如果,我遇见这样的代码,我第一反应就是,要!死!啦!. 所以,为了让你的程序人性化,我们可以使用return 语句进行改写。 我们可以对条件判断的逻辑进行分析,可以看出,里面如果条件不满足都是返回false,那么我们可以将false的情况提取出来。

function move(obj){
        if(!obj.isShow){
                return false;
        }
        if(!obj.isTop){
                return false;
        }
        if(!obj.isLeft){
                return false;
        }
        return move("TopLeft");
}

这是这个feel。当然,追求极致的话,我们可以看出return false,是完全一致的,当然可以将条件合并.

function move(obj){
        if(!obj.isShow||!obj.isTop||!obj.isLeft){
                return false;
        }
        return move("TopLeft");
}

其实如果你数学学得好的话(我还行吧,嘿~嘿~嘿~)。 这样提取条件的事是轻而易举的,可以看出,上面那段古老的代码完全可以变为现在这个样式,而且读起来,真的不是一个档次的。

减少参数数量

减少参数数量的方法,当然永远不会===1, 因为每个人站的角度不同,得到的答案当然也不一样。所以这里只介绍两种比较通用的。

  • 使用对象来代替参数列表。
  • 将需要额外计算的参数忽略。

使用对象代替参数

这个最突出的特点就是在写模板的时候。

function templ(name,age,gender){
        return `my name is ${name}. and I'm ${age} years old. yeah! I am a ${gender}`;
}

有一个模板,上面需求的参数有三个,但是,事实上,这个是完全不靠谱的。 因为一个人不仅仅只有name,age,gender 肯定还有别的参数,这样,造成的后果就是,你一直在维护模板的同时,还需要维护参数列表。而且,还要维护,传入参数的顺序的正确性。所以这里强烈推荐使用对象来代替多参数。

function templ(person){
        return `my name is ${person.name}. and I'm ${person.age} years old. yeah! I am a ${person.gender}`;
}

现在这个模板函数与外界的耦合性已经降低了不少。而且非常易于维护,就算外面你的person对象有多余的参数,也不会妨碍我使用我需要的数据。

忽略额外计算的参数

这种情况主要是在做UI的时候可能会遇到,即,想绘制一个数据table的时候,需要将一个数据矩形的高,宽以及面积传入一个函数,进行绘制。

function column(width,height,square){
        console.log("矩形的宽度为"+width);
        console.log("矩形的高度为"+height);
        console.log("矩形的面积为"+square);
}

而,这样做是完全没有必要的,因为函数参数越少,给人的感觉当然越好。 我们可以修改为这样.

function column(width,height){
        var square = width*height;
        console.log("矩形的宽度为"+width);
        console.log("矩形的高度为"+height);
        console.log("矩形的面积为"+square);
}

而且在插件设计中,也应该准遵守这个原则,函数的参数应该在能力范围内,把它降至最少。

链式调用

这个应该算是比较高级的用法。使用过jQuery的同学应该印象最深刻。 即,我们可以这样来使用一个功能. $(".myClass").addClass("show").attr('data-name').css("display","none"); 而这样实现其实并不难,只要在每个方法的后面返回该对象就可以实现这个技能。 我们来模仿一下。

var Div = function(){

}
Div.prototype.createElement = function(){
        console.log("创建一个Div");
        return this;
}
Div.prototype.showDiv = function(){
        console.log("显示Div");
        return this;
}
var div = new Div();
div.createElement().showDiv();

这样不仅可以实现对象的细粒度,而且也满足单一职责原则。 同样,我要说的是,以为的使用链式的时候,记住,使用一个功能块链式调用一定要分行,不然,调bug会调哭的。

var Div = function(){

}
Div.prototype.createElement = function(){
        console.log("创建一个Div");
        return this;
}
Div.prototype.showDiv = function(){
        console.log("显示Div");
        return this;
}
Div.prototype.hideDiv = function(){
        console.log("隐藏Div");
        return this;
}
Div.prototype.tagName = function(){
        console.log("tagName 是 Div");
        return this;
}
var div = new Div();
div.createElement().showDiv().tagName().hideDiv();  //表这样做

上面是个反例,正确的做法,应该分开。

div.createElement()
.showDiv()
.tagName()
.hideDiv();

像这样调用,万一出个Bug,你也应该知道这个bug在哪一个函数块内。 大部分重构的小技巧差不多介绍完了(智商有限),如果,大家有什么更好的建议欢迎留言反馈.

原文出处:IVWEB社区 未经同意,禁止转载

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏hrscy

在unity中使用三种简单的方式实现实时时钟动画

在 unity 中,材质是用来给一个对象的细节,所以我们可以决定它会看起来像什么。在大多数情况下,材料将以纹理为参数。

31520
来自专栏GreenLeaves

FactoryMethod工厂方法模式(创建型模式)

整个抽象的游戏设施建造系统相对变化较慢,本例中只有一个Build的创建方法,而Build内部的方法实现,该实现依赖与各种具体的实现,而这些实现变化的非常频繁,现...

7920
来自专栏计算机视觉与深度学习基础

模拟猜单词游戏

模拟实现猜单词游戏,纯模拟,不涉及图形界面,注释很详细,虽然本人代码写得丑,但是希望可以给大家提供帮助 #include<algorithm> #include...

216100
来自专栏数据小魔方

教你如何优雅的用R语言调用有道翻译

最近刚发现了个有趣的包,一个R语言发烧友开发了R语言与有道在线翻译的接口,可能这位大神也是一个受够了每天打开网页狂敲键盘查词的罪,索性自己动手,从此丰衣足食。 ...

25330
来自专栏大数据文摘

如何利用维基百科的数据可视化当代音乐史

20670
来自专栏编程

用JS 封装类似于JQ中animate的动画效果

前言:现在网上对这种类似的代码繁多,但是都是各家所长,希望源码时代H5前端讲师写的代码能够帮助到需要这样效果的朋友。 首先说一下,这篇文章对初学者有很大的帮助,...

28150
来自专栏lhyt前端之路

(VUE!jQuery!插件!)盘点前端群的无脑回答0.前言总结

你是不是在前端群见过很多这种前景:这个怎么做?怎么拿到这些数据?怎么更新整个列表?

19840
来自专栏葡萄城控件技术团队

ActiveReports 报表应用教程 (9)---交互式报表之动态排序

在葡萄城ActiveReports报表中除了提供对数据源进行排序的功能之外,还提供了最终用户排序功能,最终用户可以对报表进行区域内排序和整个数据源排序,结合数据...

188100
来自专栏炉边夜话

VC++ MFC 常用技巧 (一)

 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

14010
来自专栏积累沉淀

Java设计模式(十三)----策略模式

策略模式 一、概述 二、策略模式的结构 三、具体案例 四、认识策略模式 一、概述 1.定义 策略模式属于对象行为型模式,主要针对一组算法...

23460

扫码关注云+社区

领取腾讯云代金券