函数式编程不仅限于使用
reduce
、
filter
和
map
;它是关于函数的。这意味着我们不必依赖于奇怪的知识,比如
Array.from ({ length: x })
,其中一个带有
length
属性的对象可以被视为数组。这种行为对于初学者来说很困惑,对于其他人来说则增加了心理负担。我认为你会喜欢编写更清晰表达你意图的程序。
reduce
从 1 个或多个值开始缩减到(通常)一个值。在这种情况下,你实际上想要的是
反转 reduce
(或称为
fold
),这里称为
unfold
。区别在于我们从单个值开始,将其扩展或
展开 成(通常)多个值。
我们以一个简化的例子
alphabet
开始展开。我们从初始值
97
开始展开,这是字母
a
的字符代码。当字符代码超过
122
,即字母
z
的字符代码时,我们停止展开。
const unfold = (f, initState) =>
f ( (value, nextState) => [ value, ...unfold (f, nextState) ]
, () => []
, initState
)
const alphabet = () =>
unfold
( (next, done, char) =>
char > 122
? done ()
: next ( String.fromCharCode (char)
, char + 1
)
, 97
)
console.log (alphabet ())
上面,我们使用一个整数作为状态,但其他展开可能需要更复杂的表述。下面,我们通过展开一个由“[n,a,b]”组成的复合初始状态来显示经典的斐波那契数列,其中n是递减计数器,而a和b是用于计算序列项的数字。这说明了unfold可以与任何种子状态一起使用,甚至是数组或对象。
const fib = (n = 0) =>
unfold
( (next, done, [ n, a, b ]) =>
n < 0
? done ()
: next ( a
, [ n - 1, b, a + b ]
)
, [ n, 0, 1 ]
)
console.log (fib (20))
现在我们有信心编写“分页”功能。同样,我们的初始状态是复合数据“[ page, count ]”,因为我们需要跟踪要添加的“page”以及我们已经添加了多少个页面(“count”)。
这种方法的另一个优点是,您可以轻松地将诸如“10”、“-5”或“+1”之类的参数化,并且有一个明智、语义化的结构来放置它们。
const unfold = (f, initState) =>
f ( (value, nextState) => [ value, ...unfold (f, nextState) ]
, () => []
, initState
)
const pagination = (totalPages, currentPage = 1) =>
unfold
( (next, done, [ page, count ]) =>
page > totalPages
? done ()
: count > 10
? done ()
: next (page, [ page + 1, count + 1 ])
, [ Math.max (1, currentPage - 5), 0 ]
)
console.log (pagination (40, 1))
console.log (pagination (40, 14))
console.log (pagination (40, 38))
console.log (pagination (40, 40))
上面有两种情况会导致调用
done()
函数。我们可以使用
||
将它们合并,这样代码看起来会更加清晰易懂。
const pagination = (totalPages, currentPage = 1) =>
unfold
( (next, done, [ page, count ]) =>
page > totalPages || count > 10
? done ()
: next (page, [ page + 1, count + 1 ])
, [ Math.max (1, currentPage - 5), 0 ]
)
new Array((page + 5) - (page - 5)).fill().map((d, i) => i + (page - 5))
- BenMArray.from({length: 10}, (d, i) => i + (page - 5))
。该代码段可以用来生成一个长度为10的数组,其中每个元素的值都等于它的索引加上一个偏移量(page-5)。 - Sebastian Simon(page + 5) - (page - 5)
总是等于10
吗? - Marknew Array((page + 5) - (page - 5)).fill().map((d, i) => i + (page - 5)).filter(n => 1 <= n && n <= lastPage )
- Mark Kvetny