前端代码之丑(1):分支化技巧
by lifesinger
at 2010-11-26 22:47:32
original http://lifesinger.org/blog/2010/11/fed-ugly-code-1/
看了 InfoQ 的 代码之丑 专栏,心痒痒忍不住,前端也来一个系列吧。
分析的代码片段大都来自实际项目。还希望代码主人多多包容,让我们一起共同研究探讨,互助学习提高。
实际代码
今天要分析的是获取邮费目的地的一段代码(做了部分简化,整体保持原貌):
var DEST_MAP = { '1': '全国', '110000': '北京', '230000': '黑龙江' }; // 注:精简了数据。真实代码中,有 36 个键值对,表示全国各个省份。 var DEST_MAP_UTF8 = { '1': '全國', '110000': '北京', '230000': '黑龍江' }; var doc = document, EMPTY = ''; var charset = doc.charset || doc['characterSet'] || 'gb2312'; var isUTF8 = charset.toLowerCase().indexOf('utf-8') != -1; var getDestNameByCode = (function() { if (isUTF8) { return function(destCode) { return DEST_MAP_UTF8[destCode] || EMPTY; } } else { return function(destCode) { return DEST_MAP[destCode] || EMPTY; } } })();
淘宝的页面,有简体版和繁体版,简体版采用 GB 编码,繁体版用 UTF-8 编码。上面的代码,根据 charset 来判断是否繁体版。然后根据是否繁体版,来决定 getDestNameByCode
的定义。
冗余闭包
在 JavaScript 里,可以用闭包来封存数据。上面的代码,闭包中并没有需要封存的数据。很显然可以去掉闭包,用条件表达式来实现分支化即可:
var getDestNameByCode = isUTF8 ? function(destCode) { return DEST_MAP_UTF8[destCode] || EMPTY; } : function(destCode) { return DEST_MAP[destCode] || EMPTY; };
去掉一层冗余闭包,胃里舒服多了,但上面的代码依旧让人感觉很雷同。两个分支函数里,只有 DEST_MAP
不同。进一步优化:
var MAP = isUTF8 ? DEST_MAP_UTF8 : DEST_MAP; function getDestNameByCode(destCode) { return MAP[destCode] || EMPTY; }
差异化数据
代码越来越少,可阅读性也没降低,心情逐渐愉快起来。但一看到 DEST_MAP
和 DEST_MAP_UTF8
两大段数据,心情还是糟糟的。这两个数据对象,key 值是一样的,只有部分 val 值有繁简区别。很快想到下面的改进方式:
var doc = document, charset = doc.charset || doc['characterSet'] || 'gb2312', DEST_MAP = { '1': '全国', '110000': '北京', '230000': '黑龙江' }; if (charset.toLowerCase() === 'utf-8') { DEST_MAP['1'] = '全國'; DEST_MAP['230000'] = '黑龍江'; } function getDestNameByCode(destCode) { return DEST_MAP[destCode] || ''; }
doc
和 charset
变量在其它代码中还需要用到,保留定义。isUTF8
仅用来分支化繁简数据,直接内联化处理。
上面的代码,和原始代码相比,代码量减少了不少,可阅读性也还不错,很清晰。这样折腾后,胃里舒服多了,哈哈。
过犹不及
代码优化,要时刻权衡性能与可维护性,权衡时间和空间。从空间占用上讲,上面的数据对象还可以进一步缩减:
var DEST_MAP = { '1': ['全国', '全國'], '110000': '北京', '230000': ['黑龙江', '黑龍江'] };
然后在 getDestNameByCode
方法里,根据 isUTF8
决定获取哪一个值。这样能让整体代码更小,但增加了 getDestNameByCode
的复杂性,可阅读性也降低了,感觉过犹不及。
结语
好了,第一期前端代码之丑结束。各位朋友,谈谈你的想法?