在es6中,我们可以使用promise来解决‘回调地狱’的问题,但是在一些应用场景中我们还会遇到另一种‘地狱’:函数的深度嵌套调用,此时我们就可以用compose函数来扁平化这种调用,提升代码可读性。
提出问题
假设有这么一段代码:
function f1(data) {
console.log('f1执行')
return data+1
}
function f2(data) {
console.log('f2执行')
return data+2
}
function f3(data) {
console.log('f3执行')
return data+3
}
function f4(data) {
console.log('f4执行')
return data+4
}
现在要求执行这几个函数时要传入上一个函数的执行结果作为参数,此时代码写起来是这样的:
f1(f2(f3(f4(3))))
执行起来是没有问题,但是看起来难受且代码不好维护。
此时如果使用compose函数,代码就是这样写的:
compose(f1,f2,f3,f4)(3)
代码看起来清新很多。
compose函数执行完会返回一个新的函数,这个函数接受最初始的参数,然后将这个参数传给f4,f4执行完后把结果传给f3,依次类推,最后把f1的执行结果返回出来。有了思路,实现起来就很容易了。
代码实现
首先定义一个函数compose,首先数组化arguments 然后返回一个闭包,这个闭包接受一个参数作为嵌套调用的初始参数。
function compose(){
let fns=Array.from(arguments)
return function(data){}
}
此时fns数组是这个样子的
[f1,f2,f3,f4]
我们希望最先执行f4最后执行f1,即函数从右到左依次执行,此时就要对数组进行reverse操作,之后再对fns数组进行reduce操作,我们把闭包函数接收的参数作为reduce的初始值,并在reduce操作函数中的total作为参数传currentValue函数中并执行,最后把currentValue函数执行结果返回作为total值传入到下一次的操作中,最终代码如下:
function compose(){
let fns=Array.from(arguments)
return function(data){
return fns.reverse().reduce(function(pre,item){
return item(pre)
},data)
}
}
最后来执行一下代码:
console.log('normal')
console.log('结果是'+f1(f2(f3(f4(3)))))
console.log('useCompose')
console.log('结果是'+compose(f1,f2,f3,f4)(3))
执行结果:
实际开发中的应用
在使用react开发高阶组件时,我们除了使用装饰器的方式来对木偶组件进行增强以外,还可以使用compose来把智能组件和木偶组件链接起来以得到我们最后需要的组件。