Refactoring并不是对之前代码的全盘否定,而是更好的写出更好、更易维护的代码。不断的追求和学习,才会有更大的进步。一、前言本人从事前端开发有一段时间了。这段时间,我的要求不仅仅是项目的完成,还有功能的正常使用。我也努力研究如何编写优雅的代码、更好的性能和更可维护的代码。通俗点说就是重构。这篇文章也算是我的一个小记录,分享到这里。这篇文章主要是介绍,例子比较简单,深入和复杂的例子以后有合适的例子会写出来分享。如果你对如何写出优雅可维护的代码有自己的见解,或者有重构的能力,欢迎评论。关于重构,我准备写一个系列文章,会不定期更新,主要针对以下解决方案:逻辑混乱重构、职责分离、重构增加可扩展性、重构简化使用、代码重用重构.其中会穿插以下原则:单一职责原则、最少知识原则、开闭原则。如果大家对重构有什么好的想法,或者有什么好的例子,欢迎大家留言,留下宝贵的建议。2、什么是重构首先,重构不是重写。重构大致就是在不影响项目功能的情况下,使用一系列的重构方法来改变项目的内部结构。提高项目内部的可读性和可维护性。不管是什么项目,都有一个从简单到复杂的迭代过程。在这个过程中,在不影响项目使用的情况下,需要不断优化代码,以保持或增加代码的可读性和可维护性。这样就可以避免团队协作开发中需要大量的交流和沟通。为了加入项目的开发。3、衣服脏了为什么要重构,洗了,破了就补,不合身就扔。随着业务需求的不断增加、变更、废弃,项目的代码难免会出现缺陷,影响代码的可读性和可维护性,甚至影响项目的性能。重构的目的就是解决这些缺陷,保证代码质量和性能。但前提是不能影响项目的使用。至于重构的原因,我总结了以下几点。函数逻辑结构混乱,或者因为没有注释,即使是原代码编写者也很难理清逻辑。功能完全没有可扩展性,遇到新的变化不能灵活处理。由于对象或业务逻辑的强耦合,导致业务逻辑代码量巨大,维护时难以排查问题。重复代码太多,没有复用性。随着技术的发展,代码可能还需要修改以添加新功能。随着学习的深入,前面的代码有没有更好的解决办法。因为代码的写法,虽然功能正常使用,但是性能消耗很大,需要通过改方案来优化。项目的开发和维护周期可以看作是重构开发的一部分。通俗点说,在开发的任何时候,只要看到代码别扭,引发强迫症,就可以考虑重构。只是,在重构之前,参考以下几点。首先,重构是一件需要时间的事情。它可能比以前的开发时间需要更多的时间。其次,重构就是优化代码,前提是不影响项目的使用。***,重构的难度各不相同,可能只是稍微改动一下,难度可能会比之前的开发难度大一些。基于以上几点,你需要评估是否重构。评价指标可以参考以下几点数量:需要重构的代码是否过多。质量:可读性、可维护性、代码逻辑复杂度等问题,对代码质量的影响是否已经到了无法承受的程度。时间:是否有足够的时间进行重构和测试。效果:如果重构代码,会得到哪些改进,比如代码质量提高,性能提升,对后续功能的支持更好等。5.如何重构选择的目标,如何重构目标攻击,这是具体情况,具体分析。如“为什么重构相同”。如果您发现代码有任何问题,您可以针对该情况进行改进。重构也是写代码,但不限于写,还要整理和优化。如果说写代码需要一个“学习-理解-熟练”的过程,那么重构则需要一个“学习-感悟-突破-熟练”的过程。对于重构的情况,下面用5-1的简单例子来说明。该函数没有可扩展性。比如下面这个例子,我的一个库中的一个API//检测字符串//checkType('165226226326','mobile')//result:falseletcheckType=function(str,type){switch(type){case'email':return/^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(海峡);case'mobile':return/^1[3|4|5|7|8][0-9]{9}$/.test(str);case'tel':return/^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/.test(str);case'number':return/^[0-9]$/.test(str);case'english':return/^[a-zA-Z]+$/.test(str);case'text':return/^\w+$/.test(str);case'chinese':return/^[\u4E00-\u9FA5]+$/.test(str);case'lower':return/^[a-z]+$/.test(str);case'upper':return/^[A-Z]+$/.test(str);default:returntrue;}}这个API看起来不错,可以检测一些常用的数据。但存在以下两个问题。但是,如果您考虑添加其他规则怎么办?您必须在函数内添加大小写。添加规则,修改一次!这违反了开闭原则(对扩展开放,对修改关闭)。而这也会导致整个API变得臃肿难维护。另一个问题是,比如A页面需要添加金额验证,B页面需要日期验证,但是A页面只需要进行金额验证,B页面只需要进行日期验证。如果一直加case。就是导致A页面添加B页面才需要的校验规则,造成不必要的开销。B页面也是如此。建议的方法是给这个API添加一个扩展接口letcheckType=(function(){letrules={email(str){return/^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(str);},mobile(str){return/^1[3|4|5|7|8][0-9]{9}$/.test(str);},tel(str){return/^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/.test(str);},number(str){return/^[0-9]$/.test(str);},english(str){return/^[a-zA-Z]+$/.test(str);},text(str){return/^\w+$/.test(str);},chinese(str){return/^[\u4E00-\u9FA5]+$/.test(str);},lower(str){return/^[a-z]+$/.test(str);},upper(str){return/^[A-Z]+$/.test(str);}};//暴露的接口return{//checkcheck(str,type){returnrules[type]?rules[type](str):false;},//添加规则addRule(type,fn){rules[type]=fn;}}})();//调用方法//使用手机验证规则console.log(checkType.check('188170239','mobile'));//添加金额验证规则checkType.addRule('money',function(str){return/^[0-9]+(.[0-9]{2})?$/.test(str)});//使用金额校验规则console.log(checkType.check('18.36','金钱'));上面的代码有点多,但是也不是太难理解,而且还具有可扩展性。上面的改进其实是通过使用策略模式(将一系列算法封装起来,让算法代码和逻辑代码可以相互独立,不会影响算法的使用)来改进的。策略模式的概念理解起来有点绕口,但是看代码应该不会绕口。让我们在这里展开。在功能上,通过重构,我们可以给功能增加可扩展性,这里就实现了。但如果上述checkType是开源项目的API,重构前的调用方式为:checkType('165226226326','phone')。重构后的调用方式为:checkType.check('188170239','phone');或checkType.addRule();.如果开源项目的作者按照上面的方法重构,那么之前使用开源项目的checkTypeAPI的开发者可能就悲剧了,因为只要开发者更新项目版本,就会出现问题。因为上面的重构是不向后兼容的。如果要向下兼容,其实也不难。加个判断就行了。letcheckType=(function(){letrules={email(str){return/^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(str);},mobile(str){return/^1[3|4|5|7|8][0-9]{9}$/.test(str);},tel(str){return/^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/.test(str);},number(str){return/^[0-9]$/.test(str);},english(str){return/^[a-zA-Z]+$/.test(str);},text(str){return/^\w+$/.test(str);},chinese(str){return/^[\u4E00-\u9FA5]+$/.test(str);},lower(str){return/^[a-z]+$/.test(str);},upper(str){return/^[A-Z]+$/.test(str);}};//暴露接口returnfunction(str,type){//如果type是函数,展开规则,否则是校验数据if(type.constructor===Function){rules[str]=type;}else{returnrules[type]?rules[type](str):false;}}})();console.log(checkType('188170239','mobile'));checkType('money',function(str){return/^[0-9]+(.[0-9]{2})?$/.test(str)});//使用金额验证规则console.log(checkType('18.36','money'));这种方式可以正常运行和扩展,但是为了代码的整洁,这种写法并不优雅。因为checkType违背了功能单一的原则。承担太多责任的功能可能会在以后导致无法估量的问题,并且可能会混淆使用。面对这样的情况,个人来说,最好的理解方式是:保持checkType不做任何修改,在项目中增加一个新的API,比如checkTypOfString,将重构后的代码写入checkTypOfString。通过各种方式引导开发者少用旧的checkType,多用checkTypOfString。在后续的项目迭代中,checkType将在适当的时候被丢弃。5-2。函数违反单一原则函数违反单一原则的最后一个后果是它们会导致逻辑混乱。如果一个函数承担太多职责,试试这个:单一函数原则——一个函数只做一件事。下面的例子//输入了一批学生信息,但是数据重复,需要对数据进行去重。然后把空的信息改成机密。letstudents=[{id:1,name:'等待',sex:'男',age:'',},{id:2,name:'流浪世界',sex:'男',age:''},{id:1,name:'waiting',sex:'',age:''},{id:3,name:'红艳',sex:'',age:'20'}];functionhandle(arr){//数组去重let_arr=[],_arrIds=[];for(leti=0;i
