关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 html 最坚实的梁柱;分享,是 CSS 里最闪耀的一瞥;总结,是 JavaScript 中最严谨的逻辑。经过捶打磨练,成就了本书的中文版。本书包含了函数式编程之精髓,希望可以帮助大家在学习函数式编程的道路上走的更顺畅。比心。
译者团队(排名不分先后):阿希、blueken、brucecham、cfanlife、dail、kyoko-df、l3ve、lilins、LittlePineapple、MatildaJin、冬青、pobusama、Cherry、萝卜、vavd317、vivaxy、萌萌、zhouyao
这一步是最棘手的。所以请慢慢的用心的阅读。
让我们看看没有将
传递给柯里化函数的样子:
- listCombination(..)
- var x = curriedMapReducer(strUppercase);
- var y = curriedFilterReducer(isLongEnough);
- var z = curriedFilterReducer(isShortEnough);
看看这三个中间函数
,
- x(..)
和
- y(..)
。每个函数都期望得到一个单一的组合函数并产生一个 reducer 函数。
- z(..)
记住,如果我们想要所有这些的独立的 reducer,我们可以这样做:
- var upperReducer = x(listCombination);
- var longEnoughReducer = y(listCombination);
- var shortEnoughReducer = z(listCombination);
但是,如果你调用
,会得到什么呢?当把
- y(z)
传递给
- z
调用,而不是
- y(..)
时会发生什么呢?这个返回的 reducer 函数内部看起来像这样:
- combinationFn(..)
- function reducer(list, val) {
- if (isLongEnough(val)) return z(list, val);
- return list;
- }
看到
里面的调用了吗? 这看起来应该是错误的,因为
- z(..)
函数应该只接收一个参数(
- z(..)
),而不是两个参数(list 和 val)。这和要求不匹配。不行。
- combinationFn(..)
我们来看看组合
。我们将把它分成两个不同的步骤:
- y(z(listCombination))
- var shortEnoughReducer = z(listCombination);
- var longAndShortEnoughReducer = y(shortEnoughReducer);
我们创建
,然后将它作为
- shortEnoughReducer(..)
传递给
- combinationFn(..)
,生成
- y(..)
。多读几遍,直到理解。
- longAndShortEnoughReducer(..)
现在想想:
和
- shortEnoughReducer(..)
的内部构造是什么样的呢?你能想得到吗?
- longAndShortEnoughReducer(..)
- // shortEnoughReducer, from z(..):
- function reducer(list, val) {
- if (isShortEnough(val)) return listCombination(list, val);
- return list;
- }
- // longAndShortEnoughReducer, from y(..):
- function reducer(list, val) {
- if (isLongEnough(val)) return shortEnoughReducer(list, val);
- return list;
- }
你看到
替代了
- shortEnoughReducer(..)
里面
- longAndShortEnoughReducer(..)
的位置了吗? 为什么这样也能运行?
- listCombination(..)
因为
的“形状”和
- reducer(..)
的形状是一样的。 换句话说,reducer 可以用作另一个 reducer 的组合函数; 它们就是这样组合起来的!
- listCombination(..)
函数作为第一个 reducer 的组合函数,这个 reducer 又可以作为组合函数给下一个 reducer,以此类推。
- listCombination(..)
我们用几个不同的值来测试我们的
:
- longAndShortEnoughReducer(..)
- longAndShortEnoughReducer( [], "nope" );
- // []
- longAndShortEnoughReducer( [], "hello" );
- // ["hello"]
- longAndShortEnoughReducer( [], "hello world" );
- // []
会过滤出不够长且不够短的值,它在同一步骤中执行这两个过滤。这是一个组合 reducer!
- longAndShortEnoughReducer(..)
再花点时间消化下。
现在,把
(生成大写 reducer 的产生器)加入组合:
- x(..)
- var longAndShortEnoughReducer = y(z(listCombination));
- var upperLongAndShortEnoughReducer = x(longAndShortEnoughReducer);
正如
名字所示,它同时执行所有三个步骤 - 一个映射和两个过滤器!它内部看起来是这样的:
- upperLongAndShortEnoughReducer(..)
- // upperLongAndShortEnoughReducer:
- function reducer(list, val) {
- return longAndShortEnoughReducer(list, strUppercase(val));
- }
一个字符串类型的
被传入,由
- val
转换成大写,然后传递给
- strUppercase(..)
。该函数只有在
- longAndShortEnoughReducer(..)
满足足够长且足够短的条件时才将它添加到数组中。否则数组保持不变。
- val
我花了几个星期来思考分析这种杂耍似的操作。所以别着急,如果你需要在这好好研究下,重新阅读个几(十几个)次。慢慢来。
现在来验证一下:
- upperLongAndShortEnoughReducer( [], "nope" );
- // []
- upperLongAndShortEnoughReducer( [], "hello" );
- // ["HELLO"]
- upperLongAndShortEnoughReducer( [], "hello world" );
- // []
这个 reducer 成功的组合了和 map 和两个 filter,太棒了!
让我们回顾一下我们到目前为止所做的事情:
- var x = curriedMapReducer( strUppercase );
- var y = curriedFilterReducer( isLongEnough );
- var z = curriedFilterReducer( isShortEnough );
- var upperLongAndShortEnoughReducer = x( y( z( listCombination ) ) );
- words.reduce( upperLongAndShortEnoughReducer, [] );
- // ["WRITTEN","SOMETHING"]
这已经很酷了,但是我们可以让它更好。
是一个组合。我们可以直接跳过中间的
- x(y(z( .. )))
/
- x
/
- y
变量名,直接这么表示该组合:
- z
- var composition = compose(
- curriedMapReducer( strUppercase ),
- curriedFilterReducer( isLongEnough ),
- curriedFilterReducer( isShortEnough )
- );
- var upperLongAndShortEnoughReducer = composition( listCombination );
- words.reduce( upperLongAndShortEnoughReducer, [] );
- // ["WRITTEN","SOMETHING"]
我们来考虑下该组合函数中“数据”的流动:
作为组合函数传入,构造
- listCombination(..)
过滤器的 reducer。
- isShortEnough(..)
过滤器的 reducer。
- isShortEnough(..)
映射的 reducer。
- strUppercase(..)
在前面的片段中,
是一个组合函数,期望组合函数来形成一个 reducer;而这个
- composition(..)
- composition(..)
来源: http://www.cnblogs.com/ikcamp/p/7918852.html