分类: 新兴技术

JavaScript语言中五种消除分支的方法

最近开始使用JavaScript. 回顾了一下这几天的代码, 发现圈复杂度为1. 30几个函数40多行, 超过两行的函数都很少 (当然那种当做对象来用的函数除外, 只说实际做事的函数. 不要小看这40几行代码, 完成了5个完整的具有用户价值的功能. JavaScript的表达能力不是盖的).

由于JavaScript具备一些函数式编程语言的特征, 写出没有分支没有显式循环的代码也属正常. 但实际上多数代码还是命令式的. 命令式风格也能写出圈复杂度为1的代码, 看看都用到了哪些技巧.

多态

这种技巧在<<重构>>里提过, 跟JavaScript没有多大关系. JavaScript对Duck Typing的支持, 使得多态更容易实现. 略过

Null Object Pattern

这个也跟JavaScript没多大关系. 具体到js, 简单说就是不要出现undefined和null, 总是赋初值. string赋””, 对象赋{ }, 等等, 可以少很多判断

Dispatch Earlier, or “Boolean Parameter Considered Harmful”

这也是一种语言无关的策略. 多说几句. 简单来说就是但凡在函数内部需要根据参数进行判断走不同分支的时候, 总应该存在一个更早的时机可以把执行路径分开, 从而消除判断. 或曰早一点分开也需要判断啊! 这是对的, 但这个判断可以由用户做出, 或者在程序的配置中做出, 而无需运行时逻辑. 举个简单的栗子: 用户点击网页对话框中的”确定”和”取消”时发给server端的请求应该如何设计?

一种是发送请求到如下URL: http://my.domain/some/question?agreed=1 或者 http://my.domain/some/question?agreed=0或者post的话同一个URL不同body. 如果是这种设计, 那server端必然有一个if来判断是确定还是取消. 可用户点击的时候已经做出判断了啊, 在程序中再做一次不是很多余吗?

另一种设计会利用用户的判断, 点击”确定”或”取消”的请求会被发送到不同的URL, 从而被路由到不同的server端的代码. 处理”确定”的代码无需关心用户点击的是不是”确定”, 因为只有用户点击”确定”后请求才会被送到你那里. 类似桌面应用不同的按钮关联不同的事件处理程序.

那会不会有代码重复? 有就抽出来呗.

JavaScript 对象是天然的分发表

只有这一条跟JavaScript有点关系. JavaScript对象就是以string为key的哈希, 而JavaScript中函数可以作为值, 也就是函数可以作为哈希的value. 这让JavaScript对象成了一个天然的分发表, key进去,函数出来, 不用任何显式的if/else/switch. 举个栗子:

即时聊天机器人, 根据用户的输入做不同的动作, 比如输入天气的话, 就去查询最近的天气并返回, 输入餐馆就查询附近的餐馆并返回

var response_generators = {
  weather: function( ) { query_weather_from_weather_service… },
  restaurant: function( ) { get_local_information… },
  help: function( ) { generate_help_menu… }
}

var reply = response_generators[user.input]( );

这种方式可消除显式的分支, 并且代码描述性更强. 但有变化发生时, 依然要打开修改response_generators.

利用underscore之类的类库消除循环, 包括循环中的break和continue

var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [2, 4, 6]
Share

发表评论

评论