针针见血:如何消除JS中的代码异味

本文罗列JavaScript代码中常见的代码坏味道,如临时定时器,双向数据绑定的坑,复杂的分支语句,重复赋值等,对它们进行分析如现场还原,糟糕代码回顾,问题诊断和识别(通过ESlint或其他工具),代码重构方案,给出了怎么写好代码的一手经验~

绕来绕去,很烧脑

问题现场:

如果单词以辅音开头(或辅音集),把它剩余的步伐移到前面,并且添加上『ay』如pig -> igpay
如果单词以元音开头,保持顺序但是在结尾加上『way』如,egg->eggway等

糟糕代码:

问题在哪:

  • 太多语句
  • 太多嵌套
  • 太高复杂度

检测出问题:

关于Lint的配置项:如最大语句数,复杂度,最大嵌套数,最大长度,最多传参,最多嵌套回调

测试先行:

重构后代码:

数据对比:

max-statements: 16 → 6
max-depth: 5 → 2
complexity: 7 → 3
max-len: 65 → 73
max-params: 1 → 2
max-nested-callbacks: 0 → 1

相关资源:

jshint – http://jshint.com/
eslint – http://eslint.org/
jscomplexity – http://jscomplexity.org/
escomplex – https://github.com/philbooth/escomplex
jasmine – http://jasmine.github.io/

粘贴复制

问题现场:

我们需要实现如下的效果

糟糕的代码:

问题出在哪:

因为我们在粘贴复制!!

检测出问题:

检查出粘贴复制和结构类似的代码片段 – jsinspect
https://github.com/danielstjules

从你的JS,TypeScript,C#,Ruby,CSS,HTML等源代码中找到粘贴复制的部分 – JSCPD
https://github.com/kucherenko/jscpd

重构后代码:

  • Let’s pull out the random color portion…
  • Let’s pull out the weird [].forEach.call portion…
  • Let’s try to go further…

复杂的分支语句

糟糕的代码:

问题出在哪:

违反了 open/close 原则:

软件元素(类,模块和方法等)应该易于被打开扩展,但是除了本身不要多于的修改。既代码本身可以允许它的行为被扩展,但是不要修改源代码

可以使用诸如检查:
no-switch – disallow the use of the switch statement
no-complex-switch-case – disallow use of complex switch statements

重构后代码:

这时候添加一个代码就不像之前那样该原先的switch,直到它又长又臭,还容易把之前的代码逻辑broken掉。

魔法数字/字符串的坏味道

糟糕代码:

如上面看到的,如Magic Strings,对于诸如Triangle,Square这些就是特殊字符串。

问题出在哪:

这些魔法数字和字符串是直接写死在代码中,不容易修改和阅读。注入password.length > 9,这里面的9是指 MAX_PASSWORD_SIZE ,这样先定义后使用更清晰。同时如果多个地方需要这个判断规则,也可以避免多次修改类似9这样的数字

https://en.wikipedia.org/wiki/Magic_number_(programming)
http://stackoverflow.com/questions/47882/what-is-a-magic-number-and-why-is-it-bad

重构后代码:

1 通过对象

2 通过 const 和 symbols

代码深渊

糟糕代码:

问题出在哪:

奇奇怪怪的 self /that/_this 等

使用一下的eslint:

  • no-this-assign (eslint-plugin-smells)
  • consistent-this
  • no-extra-bind

重构后代码:

利用Function.bind, 2nd parameter of forEach, es6

脆裂的字符拼接

糟糕代码:

问题出在哪:

代码很丑陋,也很啰嗦,不直观。

使用 ES6的模板字符串(字符串插值和多行)
很多工具和框架也都提供了响应的支持,如lodash/underscore,angular,react 等

  • no-complex-string-concat

重构后代码:

jQuery询问

糟糕代码:

问题出在哪:

太多的链式调用

重构后代码

临时定时器

糟糕代码:

问题出在哪:

out of sync timer 不能确认时序和执行

重构后代码:

等 3s 去执行timer(setTimeout),然后调用 someLongProcess (long process: random time ),接着在循环
使用setInterval fn(其中在进行 long process),还是通过callback传递来反复setTimeout(timer, )

重复赋值

糟糕代码:

问题出在哪:

有些重复和啰嗦

eslint-plugin-smells

  • no-reassign

重构后代码:

1 嵌套的函数调用
2 forEach
3 reduce
4 flow

不合理的情报

糟糕代码:

问题出在哪:

依赖被紧紧的耦合了
相互调用,耦合!如 product 和 shoppingCart 关系

重构后代码:

1 dependency injection 依赖注入
2 消息经纪人broker

不断的交互调用

糟糕代码:

问题出在哪:

会造成卡顿,多余的计算等

重构后代码:

throttle 和 debounce

匿名算法

糟糕代码:

问题出在哪:

匿名函数是个好东西,但是给函数命名可以帮助我们:

  • Stack Trace(结合Devtools,跟容易debug)
  • Dereferencing
  • Code Reuse

重构后代码:

未明确的执行

糟糕代码:

明确触发时机而不是,写在 domready

问题出在哪:

很难做单元测试

重构后代码:

利用单例模块,加上构建器函数
单例模式(单例有个init 方法,来Kick off) & 构造函数(new Application() -> 在原来的构造函数中Kick off your code!)

双向数据绑定

糟糕代码:

随便看看你们手头的MVVM项目(如Angular的等)

问题出在哪:

很难定位执行顺序和数据流(Hard to track execution & data flow )
(也是Angular1.x被大力吐槽的地方,被React的Flux)

重构后代码:

方案: flux(action, dispatcher, store->view)

React Flux
An Angular2 Todo App: First look at App Development in Angular2

结语

更多的lint规则,在npm上搜索 eslint-plugin 查找

1 6 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部