声明式编程和命令式编程是两种不同的编写逻辑的方式。声明式编程关注的是实现目标,不在乎过程。命令式编程关注的是实现的具体过程。
不容易理解?来看几个例子。
例子
例子1: 办年会
年底了,公司准备举办年会。
命令式的做法:老板和HR说,
年会订在某某酒店。
搞个抽奖。一等奖 1 个,Mac pro。二等奖 3 个, ipad pro…
命令式的做法,老板和 HR 说的是年会的具体过程。
声明式的做法:老板和HR说,
给你 10万 预算,办一个让员工满意的年会。
声明式的做法:老板和 HR 说的是年会的目标。
例子2: 对满足条件的数组内容求和
实现这样的功能:将数组中的正数做平方,然后再求和。
命令式的做法:
const arr = [-1, -2, 1, 2, 3]
let sum = 0
arr.forEach(item => {
if(item > 0) {
sum += item * item
}
})
命令式做的是具体过程:循环数组,将正数找出来,用 sum
变量存当前的和,不断地加正数的平方。
声明式的做法:
const arr = [-1, -2, 1, 2, 3]
const sum = arr
.filter(item => item > 0)
.map(item => item * item)
.reduce((prev, current) => prev + current, 0)
声明式定义了目标:筛选正数,做平方,求和。不关注过程:如何传入过滤条件就能获得结果,如何做映射,如何将数组收敛成一个值。过程是数组的 filter
, map
, reduce
方法实现的。
在这个例子中,我们发现,声明式的代码比命令式代码逻辑清晰,可读性强。
例子3: 实现 TODO List
有一个列表。实现这样的功能:当新增,修改,删除子项目后,列表做对应的变化。
命令式的做法:给新增按钮,修改按钮,删除按钮绑点击事件。在点击事件回调里对 DOM 做对应的修改:新增元素,修改元素内容,删除元素。
声明式的做法:声明了列表数据和 DOM 的映射关系和事件绑定关系。当新增按钮,修改按钮,删除按钮被点击时,只修改列表数据。列表对应的 DOM 会被用自动更新。React,Vue 等框架都实现了声明数据和 DOM 的关系,当数据变化时,根据声明更新对应的 DOM。
试想,如果列表的 DOM 结构发生变化,使用命令式的要改 DOM 变化导致的选择器的变化。而声明式的代码不需要改。如果这个列表运行在没有 DOM 的环境(小程序,APP),使用命令式的代码就完全不能用了。而声明式的代码只要改用支持当前环境的跨端框架即可,比如 Taro[1] 等。
在这个例子中,我们发现,在环境发生变化时,声明式的代码比命令式代码改动小。
将命令式代码转化声明式代码
上面的 3 个例子,介绍了 命令式编程 和 声明式编程 的区别。以及声明式编程的优点。那么,如何将命令式代码转化声明式代码呢?
将命令式代码转化成声明式代码,就是要分离过程和目标。对过程做封装,就目标传入封装的过程中。举个例子:实现将对象的所有属性值乘2。
命令式代码这么写:
const obj = { a: 1, b: 2, c: 3 }
const res = {}
Object.keys(obj)
.forEach(key => {
res[key] = obj[key] * 2
})
上面的代码中,遍历 key,做 map 是过程。我们来该过程封装成函数:
function mapObjValue(obj, fn) => {
const res = {}
Object.keys(obj).forEach(key => {
res[key] = fn(obj[key])
});
return res
}
目标是属性值乘 2:
function mapFn = item => item * 2
组合起来,声明式代码这么写:
const obj = { a: 1, b: 2, c: 3 }
const res = mapObjValue(obj, mapFn)
总结
参考资料
Taro: http://taro-docs.jd.com/taro/docs/README
原文始发于微信公众号(前端GoGoGo):还在用命令式编程吗?优化成声明式编程吧~
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/45606.html