简单了解JavaScript中常见的反模式(2)

哈哈当你读到这一段时,相信上述注释已经成功地消耗了你的时间。 如果你第一次看到这样的注释可能会不可思议,但真实的项目中多数注释都是这个状态。 因为维护代码不一定总是记得维护注释,况且维护代码的通常不止一人。 C 语言课程的后遗症不止变量命名,“常写注释”也是一个很坏的教导。

解决办法就是用清晰的逻辑来代替注释,上述例子重新编写后的代码如下:

if (isHttpsSupported()) { // 通过函数抽取 + 命名,避免了添加注释 } function isHttpsSupported() { return navigator.userAgent.match(/Chrome:(\d+))[1] < 15 }

函数体膨胀

“通常”认为函数体膨胀和全局变量都是算法课的后遗症。 但复杂的业务和算法的场景确实不同,前者有更多的概念和操作需要解释和整理。 整理业务逻辑最有效的手段莫过于变量命名和方法抽取(当然,还要有相应的闭包或对象)。

但在真实的业务维护中,保持理性并不容易。 当你几十次进入同一个文件添加业务逻辑后,你的函数一定会像懒婆娘的裹脚布一样又臭又长:

function submitForm() { var username = $('form input#username').val() if (username === 'harttle') { username = 'God' } else { username = 'Mortal' if ($('form input#words').val().indexOf('harttle')) { username = 'prophet' } } $('form input#username').val(username) $('form').submit() }

这只是用来示例,十几行还远远没有达到“又臭又长”的地步。 但已经可以看到各种目的的修改让 submitForm() 的职责远不止提交一个表单。 一个可能的重构方案是这样的:

function submitForm() { normalize() $('form').submit() } function normalize() { var username = parseUsername( $('form input#username').val(), $('form input#words').val() ) $('form input#username').val(username) } function parseUsername(username, words) if (username === 'harttle') { return 'God' } return words.indexOf('harttle') ? 'prophet' : 'Mortal' }

在重构后的版本中,我们把原始输入解析、数据归一化等操作分离到了不同的函数, 这些抽离不仅让 submitForm() 更容易理解,也让进一步扩展业务更为方便。 比如在 normalize() 方法中对 input#password 字段也进行检查, 比如新增一个 parseWords() 方法对 input#words 字段进行解析等等。

总结

常见的反模式还有许多,比如 == 和 != 的使用;扩展原生对象;还有 Promise 相关的 等等。

== 要提一下。这是语言的设计缺陷通常使用 Lint 工具来避免使用。与其他 Lint 错误不同的是一旦开始大面积使用后续改正十分困难(因为与 === 确实不等价)。因此强烈建议项目初始化时就添加 Lint。

这些反模式的流行背后都存在很有说服力的原因, 但反模式对可维护性和软件的长期发展有着更为严重的影响。 按照 技术债务 的说法, 每次选择捷径都会产生隐含的代价,而这些代价在将来的某一时刻总要偿还。 那些推迟的重构不仅会影响下一次变更,而且会像经济债务一样持续地叠加利息。

虽然不存在一种具体的考核方法来计算债务大小, 但可以肯定的是如果你能熟练使用 Harttle 博客中总结的各种反模式, 一定能达到每次代码提交债务大于收益的境界。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/72208e3b8ae2b85a9842fed1b6fa06ba.html