原文地址
https://medium.com/free-code-camp/pipe-and-compose-in-javascript-5b04004ac937
Pipe
管道的概念很简单,它结合了多个功能,是一条从左到右的管道,调用每一个函数并返回最终的结果。
编写一个返回某人姓名的函数
const getName = person => person.name
getName({name: 'DonaldJTrump'}) // DonaldJTrump
编写一个返回大写字符串的函数
const getUppercase = str => str.toUpperCase()
getUppercase("DonaldJTrump") // DONALDJTRUMP
所以如果我们想获取大写的人名,我和可以这样做
const getName = person => person.name
const getUppercase = str => str.toUpperCase()
getUppercase(getName({name: 'DonaldJTrump'})) // DONALDJTRUMP
看起来没有问题,但是我不是很喜欢这样的嵌套,如果我们想添加更多的处理函数,它就会变得越来越拥挤,比如:
const getName = person => person.name
const getUppercase = str => str.toUpperCase()
// 获取字符串前六位
const get6Characters = str => str.substring(0, 6)
get6Characters(getUppercase(getName({name: 'DonaldJTrump'}))) // DONALD
如果有更多的处理函数,这样的嵌套只会显得更拥挤并难以维护,这时候我们就需要Pipe来救场了
const getName = person => person.name
const getUppercase = str => str.toUpperCase()
const get6Characters = str => str.substring(0, 6)
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x)
pipe(
getName,
getUppercase,
get6Characters
)({name: 'DonaldJTrump'}) // DONALD
一样的效果,但是这个看起来是不是更优雅一点:)
Compose
Compose只是不同方向的Pipe,它从右向左执行
const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x)
更多用法
const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x)
const map = cb => arr => arr.map(cb)
const filter = cb => arr => arr.filter(cb)
const users = [{name: "张三", age: 20}, {name: "李四", age: 20}, {name: "王五", age: 18}]
compose(
map(p => p.name),
filter(p => p.age > 18)
)(users) // [ '张三', '李四' ]
高级用法
const compose2 = (...fns) => x => {
let index = -1
function dispatch(i) {
if (i <= index) return Promise.reject(new Error("called mutiple times"))
index = i
let fn = fns[i]
if (!fn) return Promise.resolve()
try {
fn(x, dispatch.bind(null, i + 1))
return Promise.resolve(x)
} catch (err) {
return Promise.reject(err)
}
}
return dispatch(0)
}
const addAge = (obj, next) => {obj.age = 18, next()}
const addSex = (obj, next) => {obj.sex = 'men', next()}
const addPhone = (obj, next) => {obj.phone = '10086', next()}
let res = compose2(addAge, addSex, addPhone)({name: 'lxy'})
res.then(a => console.log(a)) // { name: 'lxy', age: 18, sex: 'men', phone: '10086' }