如何在没有任何第三方库的情况下使用ES6更功能地编写以下代码?
// sample pager array
// * output up to 11 pages
// * the current page in the middle, if page > 5
// * don't include pager < 1 or pager > lastPage
// * Expected output using example:
// [9,10,11,12,13,14,15,16,17,18,19]
const page = 14 // by example
const lastPage = 40 // by example
const pagerPages = page => {
let newArray = []
for (let i = page - 5; i <= page + 5; i++) {
i >= 1 && i <= lastPage ? newArray.push(i) : null
}
return newArray
}
我想避免使用Array.push,可能还有for循环,但我不确定在这种情况下如何实现它。
答案 0 :(得分:6)
const pageRange = (lastPage, page) => ((start, end) => Array.from({length: end - start + 1}, (_,i) => i + start))(Math.max(1, page - 5), Math.min(lastPage, page + 5));
const newArray = pageRange(40, 14);
这是一种纯粹的功能性方法。它使用Math.max/min
来实现边界,然后使用IIFE将这些边界传递给Array.from
,这将创建一个end - start
元素数组,并且每个元素都将成为数组中的位置增加了起始值。
PS:IMO你的代码实际上更简洁(除了那个不必要的三元组)并且比mys更具可读性,只是说......
答案 1 :(得分:4)
功能编程不限于reduce
,filter
和map
;关于功能。这意味着我们不必依赖像Array.from ({ length: x })
这样的反常知识,其中具有length
属性的对象可以被视为数组。对于初学者来说,这种行为是令人困惑的,而对于其他任何人来说都是精神上的开销。它认为你会喜欢编写更清晰地编码你的意图的程序。
reduce
以1个或多个值开头,并减少为(通常)单个值。在这种情况下,您实际上需要reduce
(或fold
)的反向,此处称为unfold
。不同之处在于我们从单个值开始,并将展开扩展为(通常)多个值。
我们从一个简化的例子alphabet
开始。我们开始展开初始值97
,即字母a
的字符代码。当char代码超过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) // value to add to output
, char + 1 // next state
)
, 97 // initial state
)
console.log (alphabet ())
// [ a, b, c, ..., x, y, z ]
的字符代码。
[ n, a, b ]
&#13;
上面,我们对我们的状态使用单个整数,但其他展开可能需要更复杂的表示。下面,我们通过展开n
的复合初始状态来展示经典的斐波那契序列,其中a
是递减计数器,而b
和unfold
是用于计算序列的数字& #39;条款。这表明const fib = (n = 0) =>
unfold
( (next, done, [ n, a, b ]) =>
n < 0
? done ()
: next ( a // value to add to output
, [ n - 1, b, a + b ] // next state
)
, [ n, 0, 1 ] // initial state
)
console.log (fib (20))
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765 ]
可以用于任何种子状态,甚至是数组或对象。
pagination
现在我们有信心写[ 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))
// [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ]
console.log (pagination (40, 14))
// [ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ]
console.log (pagination (40, 38))
// [ 33, 34, 35, 36, 37, 38, 39, 40 ]
console.log (pagination (40, 40))
// [ 35, 36, 37, 38, 39, 40 ]
之类的内容进行参数化,并且可以使用合理的语义结构将其置于其中。
done ()
&#13;
上面,有两个条件导致调用||
。我们可以使用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 ]
)
来折叠它们,并且代码读得更好
[node-js-getting-started]$ heroku local web
[OKAY] Loaded ENV .env File as KEY=VALUE Format
18:47:54 web.1 | Listening on 5000
答案 2 :(得分:1)
有很多方法可以在功能上创建一个数组,但是根据一些相关的项目(如数学系列)创建一个数组主要是通过展开来完成的。您可以考虑像减少的反转一样展开。你的情况不一定需要展开,但只是为了正确的函数式编程,让我们看看它是如何完成的。
JS没有本机展开功能,但我们可能只是实现它。首先,unfold
函数是什么样的..?
Array.unfold = function(p,f,t,v){
var res = [],
runner = d => p(d,res.length,res) ? [] : (res.push(f(d)),runner(t(d)), res);
return runner(v);
};
如所见,需要4个参数。
p
:这是一个回调函数,就像我们在reduce中一样。使用当前种子元素e
调用它,以便在插入之前处理它,它的索引i
将被插入,而当前可用的数组a
就像p(e,i,a)
一样。当它返回true
时,展开操作结束并返回创建的数组。f
:我们将为要构建的每个项目应用的功能。它需要一个参数,它是当前的迭代值。您可以考虑像索引值一样迭代值,但我们可以控制如何迭代它。t
:我们将应用迭代值并获取下一个迭代值的函数。对于像迭代这样的索引,这应该是x => x+1
。v
:是光荣的初始值。到目前为止一切顺利。我们如何使用unfold
来完成这项工作。首先,让我们通过一个以页面为参数的函数来找到我们的初始值。
var v = (pg => pg - 5 > 0 ? pg - 5 : 1)(page)
p
函数决定在哪里停止?
var p = (_,i) => i > 10
我们会逐页增加页面,但如果我们的值大于lastpage
,我们需要提供空值。所以f
可能看起来像
var f = (lp => v => v > lp ? null : v)(lastpage)
最后t
是我们如何增加迭代值的函数。这是x => x + 1
。
Array.unfold = function(p,f,t,v){
var res = [],
runner = d => p(d,res.length,res) ? [] : (res.push(f(d)),runner(t(d)), res);
return runner(v);
};
var v = pg => pg - 5 > 0 ? pg - 5 : 1,
p = (_,i) => i > 10,
f = lp => v => v > lp ? null : v,
t = x => x + 1,
a = Array.unfold(p,f(40),t,v(14));
console.log(a);
&#13;