pipe的概念很简单,就是将n个函数组合起来,他是一个从左到右的流,每个函数执行的时候都传入之前函数的结果。下面写一个返回一个人名字的函数:
getName = (person) => person.name;
getName({name: "Buckethead"})
// 返回 "Buckethead"
接下来写一个将字符串大写的函数
uppercase = (string) => string.toUpperCase();
uppercasse("Buckethead")
// 返回 "BUCKETHEAD"
所以为了获取大写的名字,接下来这样写:
name = getName({name: "Buckethead"})
uppercase(name);
// 返回 "BUCKETHEAD"
如果去掉name
参数,就变成:
uppercase(getName({ name: 'Buckethead' }));
这样看起来还行,但是这样变得拥挤了,如果我们再加一个函数来获取字符串的前6个字符呢?,那么使用一个函数:
get6Characters = (string) => string.substring(0, 6);
get6Characters('Buckethead');
// 'Bucket'
将上面的函数组合再一起变成了:
get6Characters(uppercase(getName({ name: 'Buckethead' })));
// 'BUCKET';
那么如果再加一个反转字符串的函数:
reverse = (string) =>
string
.split("")
.reverse()
.join("")
reverse("Buckethead")
// 'daehtekcuB'
这样的话就变成了:
reverse(get6Characters(uppercase(getName({ name: 'Buckethead' }))));
// 'TEKCUB'
接下来我们使用pipe
进行拯救上面这一串函数调用。为了不创建一连串的中间参数,让我们将这一串函数pipe
起来
pipe(
getName,
uppercase,
get6Characters,
reverse
)({name: "Buckethead"})
看起来想todo列表。
接下来一步步解析pipe做了什么,作为demo,将使用Eric Elliott’s functional programming articles.的继承。
pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x)
使用...参数,可以pipe很多个函数,每个函数接收前一个函数的返回和他的所有reduced到一个值里面。就像下面这样:
pipe(
getName,
uppercase,
get6Characters,
reverse
)({name: "Buckethead"})
// 'TEKCUB'
接下来展开pipe并且debugger这些表达式,一步一步的来看:
pipe = (...functions) => (value) => {
debugger;
return functions.reduce((currrentValue, currentFunction) => {
debugger;
return currentFunction(currentValue);
}, value);
}
使用示例中的方法来pipe,并且展开看参数:
检查本地变量。有4个函数参数,并且参数值是{name: "Buckethead"}。因为使用了变量参数,pipe
允许很多的函数作为参数使用并且会一个个循环调用他们。
接下来的debugger中,将深入到reduce,currentValue
将传递给currentFunction
并且返回。
我们看到结果是Buckethead
,因为当前函数currentFunction
是返回name函数,接下来这个函数会被返回并且去掉,意味着name
变成了一个新的currentValue
,接下来继续debugger。
现在currentValue
是Buckethead
因为这是再上一个函数中我们得到的返回。当前的currentFunction
是uppercase
,所以我们的到了BUCKETHEAD
作为currentValue
。
同样的,获取BUCKETHEAD
的前面6个字符串并且把他们交给下一个函数。
接下来调用反转字符的方法reverse
以上就是pipe执行的流程,总的来说就是将一串函数作为参数传入pipe
方法里面,然后传递一个参数进去,然后pipe
会将所有的参数函数依次执行,将上一步的返回结果传入到下一步之中。