偶然发现重构这本书推出了js版,果断入手,名书之一,尤为仍是js版本,相较于java版来讲,确定更适合前端阅读,购买来自当当。html
本书做者 马丁·福勒,主要著做有:分析模式---可重用对象模型、Kent Beck. 规划极限编程、 UML精粹---标准对象建模语言简明指南(第三版)、 企业应用架构模式以及本书。本书内容以各类代码的“坏味道”,来推动合适的重构手法,和初版内容相比,有一些部分是更新了(那些被淘汰的代码、不合适的例子)。但主体思想仍是没有变,总而言之是一本值得读的好书前端
重构,改善既有代码设计(第二版)java
下面来分享本文章核心内容,读书笔记。程序员
原文:重构技术就是以微小的步伐修改程序。若是你犯下错误,很容易即可发现它。es6
感悟:细碎的步子前进,能够使得咱们避免bug,在实际中,咱们应当是以稍大的步骤来改进,当遇到问题时,撤销咱们的更改 转而走向细碎的步子推动算法
原文:重构前,先检查本身是否拥有一套可靠的测试集,这些测试必须有自我检视能力。编程
感悟:和鲍勃大叔在代码整洁之道(clean code)中的观点一致,先编写测试,才能再开发。重构亦如此json
原文:一些重构手法也会显著地影响性能。但即使如此,我一般也不去管它,继续重构,由于有了一份结构良好的代码,回头调优其性能也容易得多设计模式
感悟:不要由于性能问题而不敢重构,一份好的代码再去调优是很容易的,更况且在如今各类缓存、压缩、浏览器的优化等加持下,真正影响性能的每每只是咱们项目中的某一小块代码数组
原文:每当感受须要以注释来讲明点什么的时候,咱们就把须要说明的东西写进一个独立函数中,并以其用途(而非实现手法)命名。咱们能够对一组甚至短短一行代码作这件事。哪怕替换后的函数调用动做比函数自身还长,只要函数名称可以解释其用途,咱们也该绝不犹豫地那么作。关键不在于函数的长度,而在于函数“作什么”和“如何作”之间的语义距离。
感悟:一个最好的程序就是不须要任何注释,本身自己就已经说明了程序的运转流程,这和在初入行时,老师让咱们多写注释,最好每一行都写的不太同样,但也不算老师或者马丁大叔说错了,初入行时,咱们什么都不懂,常常编写匪夷所思的代码,因此注释很必要,可是更好的注释是咱们自身的代码。这个在不少代码规范中或者一些优秀的代码也都是这么作的。
tips:好的代码中,注释应该是短小精悍的,应该只是咱们须要描述一些很是规作法的说明,或者隐患的说明以及咱们某些时候冒出的一些对程序有用但没有作的想法
原文:事实上,撰写测试代码的最好时机是在开始动手编码以前。当我须要添加特性时,我会先编写相应的测试代码。听起来离经叛道,其实否则。编写测试代码其实就是在问本身:为了添加这个功能,我须要实现些什么?编写测试代码还能帮我把注意力集中于接口而非实现(这永远是一件好事)。预先写好的测试代码也为个人工做安上一个明确的结束标志:一旦测试代码正常运行,工做就能够结束了
感悟:编写测试代码的最佳时机是在开始编写以前,将业务最终效果编为测试代码,有利于咱们明白咱们为何要作这个功能,须要实现什么样的东西。在做者看来,不管是新增功能、修改功能、bug fix都应该测试先行。这是一种正确的思路,也是咱们如今不少程序员中所缺乏的。大部分人作的都是先写功能,在写测试。甚至一些公司连测试代码都没有
注: 本书经典语句比较多,只挑选了其中我以为感悟最深入的五点写出
Kent Beck提出了“两顶帽子”的比喻。使用重构技术开发软件时,我把本身的时间分配给两种大相径庭的行为:添加新功能和重构。添加新功能时,我不该该修改既有代码,只管添加新功能。经过添加测试并让测试正常运行,我能够衡量本身的工做进度。重构时我就不能再添加功能,只管调整代码的结构。此时我不该该添加任何测试(除非发现有先前遗漏的东西),只在绝对必要(用以处理接口变化)时才修改测试软件开发过程当中,我可能会发现本身常常变换帽子。首先我会尝试添加新功能,而后会意识到:若是把程序结构改一下,功能的添加会容易得多,因而我换一顶帽子,作一下子重构工做。程序结构调整好后,我又换上原先的帽子,继续添加新功能。新功能正常工做后,我又发现本身的编码形成程序难以理解,因而又换上重构帽子……整个过程或许只花10分钟,但不管什么时候我都清楚本身戴的是哪一顶帽子,而且明白不一样的帽子对编程状态提出的不一样要求。
需求变化
需求的变化使重构变得必要。若是一段代码能正常工做,而且不会再被修改,那么彻底能够不去重构它。能改进之固然很好,但若没人须要去理解它,它就不会真正妨碍什么。
新需求(预备性重构)
重构的最佳时机在添加新功能以前,在动手添加新功能以前,我会看看现有的代码库,此时常常会发现:若是对代码结构作一点微调,工做会变的容易不少(旧代码重构来扩展新功能)
帮助理解的重构
我须要先理解代码在作什么,而后才能着手修改。这段代码多是我写的,也多是别人写的。一旦我须要思考“这段代码到底在作什么”,我就会自问:能不能重构这段代码,令其一目了然?我可能看见了一段结构糟糕的条件逻辑,也可能但愿复用一个函数,但花费了几分钟才弄懂它到底在作什么,由于它的函数命名实在是太糟糕了。这些都是重构的机会。
捡垃圾式重构
当我在重构过程当中或者开发过程当中,发现某一块很差,若是很容易修改能够顺手修改,但若是很麻烦,我又有紧急事情时候,能够选择记录下来(但不表明我就一点都作不到把他变好)。就像野营者的老话:至少让营地比你到达时更干净,长此以往,营地就很是干净(来自营地法则)
见机行事的重构
重构常常发生在咱们平常开发中,随手可改的地方。当咱们发现很差的味道,就要将他重构
长期的重构
能够在一个团队内,达成共识。当你们遇到时候,就改正它例如,若是想替换一个正在使用的库,能够先引入一层新的抽象,使其兼容新旧两个库的接口,而后一旦调用方彻底改成了使用这层抽象,替换下面的库就会如容易的多
复审代码(code review)时的重构
开发者与审查者保持持续沟通,使得审查者可以深刻了解逻辑,使得开发者能充分认同复审者的修改意见(结对编程)
Don Roberts给了我一条准则:第一次作某件事时只管去作;第二次作相似的事会产生反感,但不管如何仍是能够去作;第三次再作相似的事,你就应该重构正如老话说的:事不过三,三则重构
改进软件的设计(也能够说是增长程序的健壮、耐久)
经过投入精力改善内部设计,咱们增长了软件的耐久性,从而能够更长时间地保持开发的快速
使得代码更容易理解
找到潜在bug
提升编程速度
延缓新功能开发
实际上,这只是一部分不理解重构真正缘由的人的想法,重构是为了从长效上见到收益,一段优秀的代码能让咱们开发起来更顺手,要权衡好重构与新功能的时机,好比一段不多使用的代码。就不必对他重构
代码全部权
有时候咱们常常会遇到,接口发布者与调用者不是同一我的,而且甚至多是用户与咱们团队的区别,在这种状况下,须要使用函数更名手法,重构新函数,而且保留旧的对外接口来调用新函数,而且标记为不推荐使用。
分支的差别
常常会有长期不合并的分支,一旦存在时间过长,合并的可能性就越低,尤为是在重构时候,咱们常常要对一些东西进行更名和变化,因此最好仍是尽量短的进行合并,这就要求咱们尽量的将功能颗粒化,若是遇到还没开发完成且又没法细化的功能,咱们能够使用特性开关对其隐藏
缺少一组自测试的代码
一组好的测试代码对重构颇有意义,它能让咱们快速发现错误,虽然实现比较复杂,但他颇有意义
遗留代码
不可避免,一组别人的代码使得咱们很烦恼,若是是一套没有合理测试的代码则使得咱们更加苦恼。这种状况下,咱们须要增长测试,能够运用重构手法找到程序的接缝,再接缝处增长测试,虽然这可能有风险,但这是前进所必需要冒的风险,同时不建议一气呵成的把整个都改完,更倾向于可以逐步地推动
本书之中的核心之一:简单来讲就是碰到什么样子的代码,你就须要警戒起来,须要进行重构了!
本文章中主要分红三部分进行描述,第一部分为名字就是它的术语,第二部分为详解:它的描述及一些实际场景,第三部分重构:就是他的参考重构手法,但这些手法仅做为参考,有时咱们可能会须要更多的手法
神秘命名
详解:也包含那些随意的abc或者汉语拼音,总之一切咱们看不懂的、烂的都算,好的命名能节省咱们很大的时间
重构:改变函数声明、变量更名、字段更名
重复代码
详解:天然这个就好理解了,只要是咱们看到两段类似的语法均可以肯定为这段代码能够提炼,一般提炼出来会更好,固然这个要看具体状况,我的感受真的遇到那种只有两处,且代码使用地方八杆子打不着,在代码稳按期间也不用浪费这个时间(这个时间不止体如今改动过程,也包括你可能由于改动致使的隐藏bug,尤为是系统核心模块,一旦出现问题只能立刻回滚,不会给你时间去找问题
重构:提炼函数、移动语句、函数上移等手法
过长的函数
描述:短小才是精悍!好比一些条件分支、一个函数作了不少事情、循环内的处理等等的都是应该重构的
重构:提炼函数(经常使用)、以查询取代临时变量、引入参数对象、保持对象完整性、以命令取代参数(消除一些参数)、分解条件表达式、以多态取代条件表达式(应对分支语句)、拆分循环(应对一个循环作了不少事情)
过长的参数列表
描述:正常来讲,函数中所需的东西应该以参数形式传入,避免全局变量的使用,但过长的参数列表其实也很恶心。
重构:查询取代参数、保持对象完整、引入参数对象、移除标记参数、函数组合成类
全局数据
描述:最多见的就是全局变量,但类变量与单例模式也有这样的问题,咱们一般没法保证项目启动后不被修改,这就很容易形成诡异的bug,而且很难追查到
重构:封装变量
可变数据
描述:数据的可变性和全局变量同样,若是我其余使用者修改了这个值,而引起不可理喻的bug。 这是很难排查的。
重构:封装变量,拆分变量,移动语句、提炼函数,查询函数和修改函数分离,移除设值函数,以查询取代变量函数组合成类
发散式变化
描述:发散式变化是指某个模块常常由于不一样的缘由在不一样的方向上变化了(能够理解为某一处修改了,形成其余模块方向错乱)
重构:拆分阶段、搬移函数、提炼函数、提炼类
霰弹式修改
描述:和发散式变化接近,却又相反。咱们每次修改一个功能或者新增一个功能都须要对多处进行修改;而且随着功能增多咱们可能还须要修改更多。 这样程序时是很不健康的,其实我我的理解为:霰弹用来描述发散式变化更好,想一想霰弹是一个点发射出去变成不少。而本条应该用另外一个词来描述更好,但我还想不到叫什么词。或许叫多路并进?仅限我的观点,每一个人理解可能不同,建议以做者为准
重构:搬移函数、搬移字段、函数组合成类、函数组合成变换、拆分阶段、内联函数、内联字段
依恋情结
描述:一个模块内的一部分频繁的和外面的模块进行交互沟通,甚至超过了它与内部的沟通。也就是违反了高内聚低耦合,遇到这种的“叛乱者”,不如就让他去他想去的地方吧
重构:搬移函数、提炼函数
数据泥团
描述:杂合缠绕在一块儿的。代码中也如是,咱们可能常常看到三四个相同的数据,两个类中相同字段等等。总之像泥同样,这里也是这样那里也是这样,就是他了
重构:提炼类、引入参数对象、保持对象完整性
基本类型偏执
描述:一些基本类型没法表示一个数据的真实意义,例如电话号码、温度等,
重构:以对象取代基本类型、以子类取代类型码、以多态取代条件表达式
重复的switch
描述:不仅是switch,大片相联的if也应该包含在内,甚至在古老的前端时代,曾经一度无条件反对这样的写法。
重构:多态取代条件表达式
循环语句
描述:在js中体现为传统的for类循环
重构:用管道来取代循环(管道:map、forEach、reduce、filter等一系列)
冗赘的元素
描述:元素指类和函数,可是这些元素可能由于种种缘由,致使函数过于小,致使没有什么做用,以及那些重复的,均可以算做冗赘
重构:内联函数、内联类、折叠继承类
夸夸其谈通用性
描述:为了未来某种需求而实现的某些特殊的处理,但其实可能致使程序难以维护难以理解,直白来讲就是没个锤子用的玩意,你留下他干个屁
重构:折叠继承体系、内联函数、内联类、改变函数声明、移除死代码
临时字段
描述:那些自己就足以说明本身是谁的,不须要名字来描述的
重构:提炼类、提炼函数、引入特例
过长的消息链
描述:一个对象请求另外一个对象,而后再向后者请求另外一个对象,而后再请求另外一个对象……这就是消息链,举个例子来讲
new Car().properties.bodyWork.material.composition().start()
这意味着在查找过程当中,不少的类耦合在一块儿。我的认为,不只是结构的耦合,也很难理解。这也包含某类人jq的那一大串的连续调用。都是很难让人理解的。
重构: 隐藏委托关系、提炼函数、搬移函数
中间人
描述:若是一个类有大部分的接口(函数)委托给了同一个调用类。当过分运用这种封装就是一种代码的坏味道
重构:移除中间人、内联函数
内幕交易
描述:两个模块的数据频繁的私下交换数据(能够理解为在程序的鲜为人知的角落),这样会致使两个模块耦合严重,而且数据交换隐藏在内部,不易被察觉
重构:搬移函数、隐藏委托关系、委托取代子类、委托取代超类
过大的类
描述:单个类作了过多的事情,其内部每每会出现太多字段,一旦如此,重复代码也就接踵而至。这也意味着这个类毫不只是在为一个行为负责
重构:提炼超类、以子类取代类型码
殊途同归的类
描述:两个能够相互替换的类,只有当接口一致才可能被替换
重构:改变函数声明、搬移函数、提炼超类
纯数据类
描述:拥有一些字段以及用于读写的函数,除此以外一无可取的类,通常这样的类每每半必定被其余类频繁的调用(若是是不可修改字段的类,不在此列,不可修改的字段无需封装,直接经过字段取值便可),这样的类每每是咱们没有把调用的行为封装进来,将行为封装进来这种状况就能获得很大改善。
重构:封装记录、移除取值函数、搬移函数、提炼函数、拆分阶段
被拒绝的遗赠
描述:这种味道比较奇怪,说的是继承中,子类不想或不须要继承某一些接口,咱们能够用函数下移或者字段下移来解决,但不值得每次都这么作,只有当子类复用了超类的行为却又不肯意支持超类的接口时候咱们才应该作出重构
重构:委托取代子类、委托取代超类
注释
描述:这里提到注释并不是是说注释是一种坏味道,只是有一些人常常将注释看成“除臭剂”来使用(一段很长的代码+一个很长的注释,来帮助解释)。每每遇到这种状况,就意味着:咱们须要重构了
重构:提炼函数、改变函数声明、引入断言
若是说上面的味道是核心的话,那手法应该就是本书的重中之重。一般咱们发现哪里味道不对以后,就要选择使用不一样的手法进行重构。将他们变得味道好起来。
本文中每一个手法一般包含三个模块:时机(遇到什么状况下使用)、作法(详细步骤的归纳)、关键字(作法的缩影)
关键字:
新函数、拷贝、检查、做用域/上下文、编译、替换、修改细节
时机:
作法:
关键字:
检查多态、找调用并替换、删除定义
反作用、不可修改的变量、赋值、替换
反作用、只读、替换变量
最好能把大的修改拆成小的步骤,因此若是你既想修改函数名,又想添加参数最好分红两步来作。 不论什么时候,若是遇到了麻烦,请撤销修改,并改用迁移式作法)
使用变量者、函数调用者、修改函数、声明更名、调用替换
内部重构、提炼新函数、好搜索的临时名字、变动、改变调用、旧函数使用新函数、改变调用名字
新函数、替换调用、不可见
针对普遍使用的
1.1 先用封装变量手法封装
1.2 找到全部使用该变量的代码,修改测试(若是是对外已发布的变量,能够标记为不建议使用(做者没提到,可是我的感受是能够这样的)
1.3 测试
只做用于某个函数的直接替换便可
替换过程当中能够以新名字做为过渡。待所有替换完毕再删除旧的名字
封装变量手法、替换名字、中间过渡
建立一个合适的数据结构(若是已经有了,能够略过)
数据结构选择:一种是以对象的形式,一种是以类的形式,做者推荐以类的形式,可是在我看来,要根据场景,若是这组数据以及其相关行为能够变为一组方法,如数组类里面的比较两个数组是否彻底一致,这就能够以类来声明(js中也能够以export来导出而使用)
使用改变函数声明手法给原函数增长一个参数为咱们新的结构
测试
旧数据中的参数传到新数据结构(变动调用方)
删除一项旧参数,并将之使用替换为新参数结构
测试
重复五、6
新结构、增长参数、入参新结构、删除旧参数、使用新结构
提炼变量、封装成类、移入已有函数、替换调用、移入计算数据
变换函数、变换入参、搬移计算逻辑
转化函数、取值函数、设值函数、替换调用者、替换设置者
新类、取设值函数、行为入类、扩展类
只读、提炼函数、删变量
职责边界确认、建立新域、新旧同步初始化、行为搬家、接口删除
代理、修改调用者、方法搬家、抛弃旧类
委托函数、替换调用者、删除委托整个类
委托整个类、修改调用、删除代理
算法封装、编写新算法、替换算法、比较算法
肯定关系、肯定继承、优先基础、函数搬家、相关部分位置肯定、原址代理、优化新函数
封装、新字段、源址代理、代理新址、旧字段移除、肯定是否内联
代码靠近、单点提炼、中间函数、修改引用、函数内联、原函数删除、函数更名
tips: 本手法只适合边界有些许偏移的场景,不适合相差较大的场景
提炼不变的为临时方法、搬移语句、删除原,更名字
内联替换
肯定反作用、肯定目标
复制循环、行为拆分、函数提炼
新变量、合适的管道、删除整个循环
检查引用
新变量、赋值时声明、替换调用
封装、兼容初始化、内部取设只返回新字段,修改内部调用,测试、删除兼容、内部取设更名、替换外部调用
tips:计算的参考变量,是不可变的,计算结果也是不可变的。能够不重构(仍是那句话,不可变的数据,咱们就不必理他)
来源肯定、结果相同、计算函数、清理更新点
值对象:a.b=new b(1) 引用对象:a.b.c=1
不可变、替换设置引用值为设置值
共享仓库、单例的引用对象、替换调用点
提炼分支、提炼条件、优化判断
分离反作用、合适的逻辑符、提炼条件函数
从外而内
肯定现有的条件类是否具备多态性,若是没有,能够经过将行为封装成类(借助其余手法如函数组合成类等)
在调用方使用工厂函数得到行为对象的实例
针对不一样类型建立子类(至关于在超类在分化)
调用方此时应当经过一个工厂返回合适的子类
将超类中针对子类类型所作的判断,逐一移入对应子类进行复写(相关子类复写超类的分支函数),超类只留下默认值
注意:这种手法实际上是在面向对象开发中很经常使用的一种方式,可是若是不是
不如将其经过一个json或者map来进行指责划分。在js中我以为更经常使用的是以策略来代替if
多态、继承、封装、行为拆分
数据结构的调用者都在检查某个特殊值,而且这个值每次所作的处理也都相同
多处以一样方式应对同一个特殊值
三种状况
第一种原始为类,特例元素没有设置值的操做
第二种原始为类,特例元素有设置值的操做
第三种 原始就是普通的json
针对于有本身对应行为的类
在原类中为特例元素增长一个函数,用以标记这个特例的状况,默认返回一个写死的就行)
为特例建立一个class,用以处理特例的正常逻辑和行为,须要把特例对象及其全部行为放到这个类
将本次特例的条件使用提炼函数手法抽成一个在类中的字段函数返回true
修改全部调用者为第3步的函数
修改第一步建立的类。让它返回咱们的特例对象
特例中的其余字段
针对于只读的类
针对于原始不是类的
为特例对象建立一个函数,返回特例对象的深拷贝状态
将本次特例的条件使用提炼函数手法抽成一个统一的函数
对第一步建立的函数返回值作特殊加强。 将须要的特例的值,逐一放进来。
替换调用者使用函数的返回值
特例逻辑搬到class、过渡函数、替换调用者、修改新class
新函数为查找、删除设置值、替换调用者、删除返回值、优化
调用较少、变化点入参、修改调用、替换使用
针对参数的每一种可能值,新建一个明确函数(若是参数控制整个流程,则能够用分解条件表达式手法建立明确函数,若是只控制一部分函数则建立转发函数,将这些函数,统一经过这些明确函数进行转发)
替换调用者
tips:若是是这个标记即做为标记,又做为参数值。则对其进行拆分。
流程、行为拆分
接受完整对象、新调用老、修改调用、内联、更名
一言以概之:这个函数自身或者经过参数都能获得另外一个值就能够使用这个手法
提炼变量、参数消除
变量提炼、函数体换新、旧函数传参、旧函数调新函数,删除代理函数、函数更名
tips:能够批量操做多个设值函数。
设值替换为new
工厂函数、调用类、替换调用
新的类、函数搬家、原类转发函数、构造入参、只读
函数体一致化、名字一致化、引用调用先行、提高函数、删除重写
一样方式使用、统一名字、字段上移、删除子类字段
构造函数内的语句上移
按需放置
直接继承超类的
间接继承(经过类型的超类而非现有超类进行继承)
封装类型码、多态化、选择子类的函数、移除类型参数
工厂函数取代子、类型提炼、检查类型判断
相同事情搬移到超类
工厂函数初始化类、委托类、全部子类数据搬移至委托类、超类增长委托类的字段、子类函数搬移到委托类、删除子类
子类属性指向超类、转发函数、去除继承
收获最大的莫过于感叹做者过于谨慎,震惊于做者重构能力之强,对代码重构理解程度之深,虽然做者有一些“墨迹”,但不能否认,这是极佳的一种方式,虽然工做中咱们不得已没有那么多时间去这么小的步子,咱们能够步子稍微大一些,当遇到问题时,在回滚并放慢步子。
第二点收获就为做者对于代码好坏的定义,好的代码就是让人可以理解,可以让人很快的找到本身要修改的地方,并能够高效的规避报错风险。虽然前期投入时间可能会多一些,但后期的效果倒是让人可以惊讶的,正如做者所说的:清晰的代码更容易理解,使你可以发现更深层次的设计问题,从而造成积极正向的循环。
做者一直在强调,重构是一步一步改进的,不是说一会儿就要如何如何,不仅是说单次改进过程要小幅度多测试,也是在说咱们不必定要将代码中全部都实现到近乎完美的地步,而是应该抉择一个代码重构与真实状况的平衡点,这和大刀阔斧直谈架构重构的也不同,代码是在不断构筑-设计中保持本身的新鲜性,直谈大型架构重构,只能是笑谈,毕竟架构为设计、编写。而直接重构整个架构,除非你想被老板炒鱿鱼了。
最后本章做者使用了不少的手法,虽然都只是一些经常使用的什么提炼函数啊、内联变量啊之类的,但到处又透露着咱们须要学习的!
重构是为了代码能被人读懂(所谓什么更好扩展啊、更好的设计模式啊、结构化啊等等等等都是为了这点。因此我统归为为了能读懂)能够选择牺牲一些(不是说能够彻底忽略了性能),毕竟在现代浏览器、打包工具的加持、缓存的加持下,肉眼看到的问题以及咱们思考的问题也许已经被各类加持下悄悄消失了
从长久来看,重构对于往后的维护往后的开发,随着时间的流逝确定是一个正收益,可是短时间来讲可能要影响咱们一些,咱们要权衡好这些点之间的平衡,毕竟工做是为了赚钱,公司也是为了盈利,不可能给咱们无限时间去搞这些,做者同时也提出了重构并非工做日志中的某一个任务的时机,主要体如今:新功能开发时、为了代码可读性、代码整合、有计划的重构代码以及坚持长期的重构以及review的重构。能够说是随时随地均可以重构,但也不是任何地方任什么时候机均可以重构,咱们要利用好测试的套件,保证原效果的前提下,结合实际状况,多维度思考,即便阅读事后,也应该时常翻开这本书,进行反复阅读,以提醒本身。
在本书中我学到了如何甄别坏的代码,以及怎么处理他们,学到了开发中应该测试先行以及一些重构的基本知识。
不过做为jser,我我的以为虽然做为一本通用型书籍,确实应该不掺杂不少的语法,不过既然选定了js,自动化重构这块其实怎么说呢,写的都是IDE。可是js中并无这类工具。而后做者也没有说在js下应该能够借助某些功能来帮助重构。因此这块仍是一片空白,虽然这种事理应本身去研究。可是仍是想免费更好嘛