|
1 |
| -#重构 |
| 1 | +#重构 |
| 2 | + |
| 3 | +或许你应该知道了,重构是怎样的,你也知道重构能带来什么。在我刚开始学重构和设计模式的时候,我需要去找一些好的示例,以便于我更好的学习。有时候不得不创造一些更好的场景,来实现这些功能。 |
| 4 | + |
| 5 | +有一天,我发现当我需要我一次又一次地重复讲述某些内容,于是我就计划着把这些应该掌握的技能放到Github上,也就有了[Artisan Stack](https://github.com/artisanstack) 计划。 |
| 6 | + |
| 7 | +每个程序员都不可避免地是一个Coder,一个没有掌握好技能的Coder,算不上是手工艺人,但是是手工人。 |
| 8 | + |
| 9 | +艺,需要有创造性的方法。 |
| 10 | + |
| 11 | +#[前端技能训练: 重构一](http://www.phodal.com/blog/frontend-improve-refactor-javascript-code/) |
| 12 | + |
| 13 | +##为什么重构? |
| 14 | + |
| 15 | +> 为了更好的代码。 |
| 16 | +
|
| 17 | +在经历了一年多的工作之后,我平时的主要工作就是修Bug。刚开始的时候觉得无聊,后来才发现修Bug需要更好的技术。有时候你可能要面对着一坨一坨的代码,有时候你可能要花几天的时间去阅读代码。而,你重写那几十代码可能只会花上你不到一天的时间。但是如果你没办法理解当时为什么这么做,你的修改只会带来更多的bug。修Bug,更多的是维护代码。还是前人总结的那句话对: |
| 18 | + |
| 19 | +> 写代码容易,读代码难。 |
| 20 | +
|
| 21 | +假设我们写这些代码只要半天,而别人读起来要一天。为什么不试着用一天的时候去写这些代码,让别人花半天或者更少的时间来理解。 |
| 22 | + |
| 23 | +如果你的代码已经上线,虽然是一坨坨的。但是不要轻易尝试,``没有测试的重构``。 |
| 24 | + |
| 25 | +从前端开始的原因在于,写得一坨坨且最不容易测试的代码都在前端。 |
| 26 | + |
| 27 | +让我们来看看我们的第一个训练,相当有挑战性。 |
| 28 | + |
| 29 | +##重构uMarkdown |
| 30 | + |
| 31 | +代码及setup请见github: [js-refactor](https://github.com/artisanstack/js-refactor) |
| 32 | + |
| 33 | +###代码说明 |
| 34 | + |
| 35 | +``uMarkdown``是一个用于将Markdown转化为HTML的库。代码看上去就像一个很典型的过程代码: |
| 36 | + |
| 37 | +```javascript |
| 38 | +/* code */ |
| 39 | +while ((stra = micromarkdown.regexobject.code.exec(str)) !== null) { |
| 40 | + str = str.replace(stra[0], '<code>\n' + micromarkdown.htmlEncode(stra[1]).replace(/\n/gm, '<br/>').replace(/\ /gm, ' ') + '</code>\n'); |
| 41 | +} |
| 42 | + |
| 43 | +/* headlines */ |
| 44 | +while ((stra = micromarkdown.regexobject.headline.exec(str)) !== null) { |
| 45 | + count = stra[1].length; |
| 46 | + str = str.replace(stra[0], '<h' + count + '>' + stra[2] + '</h' + count + '>' + '\n'); |
| 47 | +} |
| 48 | + |
| 49 | +/* mail */ |
| 50 | +while ((stra = micromarkdown.regexobject.mail.exec(str)) !== null) { |
| 51 | + str = str.replace(stra[0], '<a href="mailto:' + stra[1] + '">' + stra[1] + '</a>'); |
| 52 | +} |
| 53 | +``` |
| 54 | + |
| 55 | +选这个做重构的开始,不仅仅是因为之前在写[EchoesWorks](https://github.com/phodal/echoesworks)的时候进行了很多的重构。而且它更适合于,``重构到设计模式``的理论。让我们在重构完之后,给作者进行pull request吧。 |
| 56 | + |
| 57 | +Markdown的解析过程,有点类似于``Pipe and Filters``模式(架构模式)。 |
| 58 | + |
| 59 | +Filter即我们在代码中看到的正规表达式集: |
| 60 | + |
| 61 | +```javascript |
| 62 | +regexobject: { |
| 63 | + headline: /^(\#{1,6})([^\#\n]+)$/m, |
| 64 | + code: /\s\`\`\`\n?([^`]+)\`\`\`/g |
| 65 | +``` |
| 66 | +
|
| 67 | +他会匹配对应的Markdown类型,随后进行替换和处理。而``str```,就是管理口的输入和输出。 |
| 68 | + |
| 69 | +接着,我们就可以对其进行简单的重构。 |
| 70 | + |
| 71 | +###重构 |
| 72 | + |
| 73 | +(ps: 推荐用WebStrom来做重构,自带重构功能) |
| 74 | + |
| 75 | +作为一个示例,我们先提出codeHandler方法,即将上面的 |
| 76 | + |
| 77 | +```javascript |
| 78 | +/* code */ |
| 79 | +while ((stra = micromarkdown.regexobject.code.exec(str)) !== null) { |
| 80 | + str = str.replace(stra[0], '<code>\n' + micromarkdown.htmlEncode(stra[1]).replace(/\n/gm, '<br/>').replace(/\ /gm, ' ') + '</code>\n'); |
| 81 | +} |
| 82 | +``` |
| 83 | + |
| 84 | +提取方法成 |
| 85 | + |
| 86 | +```javascript |
| 87 | +codeFilter: function (str, stra) { |
| 88 | + return str.replace(stra[0], '<code>\n' + micromarkdown.htmlEncode(stra[1]).replace(/\n/gm, '<br/>').replace(/\ /gm, ' ') + '</code>\n'); |
| 89 | + }, |
| 90 | +``` |
| 91 | + |
| 92 | +while语句就成了 |
| 93 | + |
| 94 | +```javascript |
| 95 | +while ((stra = regexobject.code.exec(str)) !== null) { |
| 96 | + str = this.codeFilter(str, stra); |
| 97 | +} |
| 98 | +``` |
| 99 | + |
| 100 | +然后,运行所有的测试。 |
| 101 | + |
| 102 | +``` |
| 103 | +grunt test |
| 104 | +``` |
| 105 | + |
| 106 | +同理我们就可以``mail``、``headline``等方法进行重构。接着就会变成类似于下面的代码, |
| 107 | + |
| 108 | +```javascript |
| 109 | +/* code */ |
| 110 | +while ((execStr = regExpObject.code.exec(str)) !== null) { |
| 111 | +str = codeHandler(str, execStr); |
| 112 | +} |
| 113 | +
|
| 114 | +/* headlines */ |
| 115 | +while ((execStr = regExpObject.headline.exec(str)) !== null) { |
| 116 | +str = headlineHandler(str, execStr); |
| 117 | +} |
| 118 | +
|
| 119 | +/* lists */ |
| 120 | +while ((execStr = regExpObject.lists.exec(str)) !== null) { |
| 121 | +str = listHandler(str, execStr); |
| 122 | +} |
| 123 | +
|
| 124 | +/* tables */ |
| 125 | +while ((execStr = regExpObject.tables.exec(str)) !== null) { |
| 126 | +str = tableHandler(str, execStr, strict); |
| 127 | +} |
| 128 | +``` |
| 129 | + |
| 130 | +然后你也看到了,上面有一堆重复的代码,接着让我们用JavaScript的``奇技浮巧``,即apply方法,把上面的重复代码变成。 |
| 131 | + |
| 132 | +```javascript |
| 133 | +['code', 'headline', 'lists', 'tables', 'links', 'mail', 'url', 'smlinks', 'hr'].forEach(function (type) { |
| 134 | + while ((stra = regexobject[type].exec(str)) !== null) { |
| 135 | + str = that[(type + 'Handler')].apply(that, [stra, str, strict]); |
| 136 | + } |
| 137 | +}); |
| 138 | +``` |
| 139 | + |
| 140 | +进行测试,blabla,都是过的。 |
| 141 | + |
| 142 | +```javascript |
| 143 | + Markdown |
| 144 | + ✓ should parse h1~h3 |
| 145 | + ✓ should parse link |
| 146 | + ✓ should special link |
| 147 | + ✓ should parse font style |
| 148 | + ✓ should parse code |
| 149 | + ✓ should parse ul list |
| 150 | + ✓ should parse ul table |
| 151 | + ✓ should return correctly class name |
| 152 | +``` |
| 153 | + |
| 154 | +快来试试吧, [https://github.com/artisanstack/js-refactor](https://github.com/artisanstack/js-refactor) |
0 commit comments