本文翻译自30-seconds-of-code,可以理解为高阶函数片段。原作者说是30s内就可以理解,而我每一个都看了几分钟。
Adapter
ary
创建一个最多接受n
个参数的函数,多余的参数将被忽略。
使用Array.prototype.slice(0,n)
和扩展运算符(...
),调用提供的函数发fn,并且最多有n个参数。
1 | const ary = (fn, n) => (...args) => fn(...args.slice(0, n)); |
call
接受一个键值和一组参数,在给定上下文时调用它们。主要用于组合。
使用闭包在调用的时候存储键值和参数。
1 | const call = (key, ...args) => context => context[key](...args); |
collectInto
将接受数组的函数变为接受变量的函数。
给定一个函数,返回一个闭包,该闭包将所有输入收集到一个接受数组的函数中。
1 | const collectInto = fn => (...args) => fn(args); |
flip
flip将函数作为参数,然后把闭包里的第一个参数作为最后一个参数。
返回一个可以接受变量输入的闭包,并展开剩余参数,之后将其变为第一个参数。
1 | const flip = fn => (first, ...rest) => fn(...rest, first); |
over
创建一个函数,调用参数中所有的函数并返回结果。
使用Array.prototype.map()
和Function.prototype.apply()
将每个函数应用于给定的参数。
1 | const over = (...fns) => (...args) => fns.map(fn => fn.apply(null, args)); |
overArgs
创建一个函数,调用参数中的函数并将闭包中的参数按提供的函数转换。
使用Array.prototype.map()
与扩展运算符(...
)将转换后的参数传递给fn
。
1 | const overArgs = (fn, transforms) => (...args) => fn(...args.map((val, i) => transforms[i](val))); |
pipeAsyncFunctions
这个函数实在是太复杂了,稍后再译。
Performs left-to-right function composition for asynchronous functions.
Use Array.prototype.reduce()
with the spread operator (...
) to perform left-to-right function composition using Promise.then()
. The functions can return a combination of: simple values, Promise
‘s, or they can be defined as async
ones returning through await
. All functions must be unary.
1 | const pipeAsyncFunctions = (...fns) => arg => fns.reduce((p, f) => p.then(f), Promise.resolve(arg)); |
pipeFunctions
按照从左到右的函数顺序执行。
借助Array.prototype.reduce()
与扩展运算符(...
)实现从左到右的函数合成。第一个(最左边的)函数可以接受一个或多个参数,其他的函数必须是一个参数。
1 | const pipeFunctions = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args))); |
promisify
转换异步函数并返回promise。
返回一个调用原始函数后的返回promise的函数。使用...rest
运算符传递所有参数。
在Node 8+,你可以使用util.promify
1 | const promisify = func => (...args) => |
rearg
创建一个调用所提供函数的函数,其参数按照指定的索引排列。
使用Array.prototype.map( )
基于indexes
对参数重新排序,并结合扩展运算符(…)将转换后的参数传递给fn
。
1 | const rearg = (fn, indexes) => (...args) => fn(...indexes.map(i => args[i])); |
spreadOver
接受一个函数并返回一个闭包,该闭包接受一组参数并映射到函数的变量。
使用闭包和扩展运算符(...
)将数组映射为函数的变量。
1 | const spreadOver = fn => argsArr => fn(...argsArr); |
unary
创建一个只接受一个参数的函数,忽略任何其他参数。
调用提供的函数fn
,只传入一个参数。
1 | const unary = fn => val => fn(val); |
Array
all
如果数组中的所有元素执行给定的函数都返回true
,则返回true
,否则返回false
。
使用Array.prototype.very()
遍历数组中的所有元素是否执行fn
返回true
。如果省略第二个参数fn
,将使用Boolean
函数作为默认值。
1 | const all = (arr, fn = Boolean) => arr.every(fn); |
allEqual
检查数组中的所有元素是否相等。
使用Array.prototype.very()
检查数组中的所有元素是否与第一个元素相同。
1 | const allEqual = arr => arr.every(val => val === arr[0]); |
any
如果数组中至少有一个元素执行给定的函数都返回true
,则返回true
,否则返回false
。
使用Array.prototype.some()
遍历集合中是否有元素调用fn
返回true
。省略第二个参数fn
,将使用Boolean
函数作为默认值。
1 | const any = (arr, fn = Boolean) => arr.some(fn); |
arrayToCSV
将二维数组转换为逗号分隔值(CSV)字符串。
使用Array.prototype.map()
和Array.prototype.join(delimiter)
将单个一维数组(行)组合成字符串。使用Array.prototype.join("\n")
将所有行组合成一个CSV字符串,用换行符分隔每行。省略第二个参数delimiter
,将使用,
作为默认分隔符。
1 | const arrayToCSV = (arr, delimiter = ',') => |
bifurcate
将值分成两组。如果filter
函数中的元素是真的,则数组中的相应元素属于第一组;否则,它属于第二组。
使用Array.prototype.reduce()
和Array.prototype.push()
根据filter
函数将元素添加到组中。
1 | const bifurcate = (arr, filter) => |
bifurcateBy
根据给定的函数将值分成两组,该函数可以指定输入数组中的元素属于哪个组。如果函数返回真,则集合元素属于第一组;否则,它属于第二组。
每个元素调用fn
得到返回值,使用Array.prototype.reduce()
和Array.prototype.push()
将元素添加到组中。
1 | const bifurcateBy = (arr, fn) => |
chunk
将数组分成指定长度的多维数组。
使用Array.from()
创建一个新的数组,该数组的长度等于要生成的块的长度。使用Array.prototype.slice()
将新数组的元素映射到一个长度为给定长度的块。如果原数组不能被平均分割,则最后一块将包含剩余的元素。
1 | const chunk = (arr, size) => |
compact
从数组中删除无效值。
使用Array.prototype.filter()
过滤掉无效值(false
, null
, 0
, ""
, undefined
, NaN
)
1 | const compact = arr => arr.filter(Boolean); |
countBy
根据给定函数对数组中的元素进行分组,并返回每个组中元素总数。
使用Array.prototype.map()
返回数组元素调用函数或属性后的值。使用Array.prototype.reduce()
创建一个对象,其中键是根据前面的值生成的。
1 | const countBy = (arr, fn) => |
countOccurrences
计算数组中某个值的出现次数。
使用Array.prototype.reduce()
,每当遇到数组中的特定值时,递增计数器。
1 | const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0); |
deepFlatten
将数组展平。
借助递归。使用Array.prototype.concat
结合空数组([]
)和扩展运算符(...
)来展平数组。递归展平作用于数组的每个元素。
1 | const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v))); |
difference
返回两个数组之间的差异。
从b
创建一个Set
,然后在a
上使用Array.prototype.filter()
来只保留b
中不包含的值。
1 | const difference = (a, b) => { |
differenceBy
将给定的函数应用于两个数组的每个数组元素后,返回两个数组之间的差异。
通过对b
中的每个元素调用fn
来创建一个Set
,然后将Array.protototype.filter()
和a
中元素调用fn
的结果结合使用,只保留先前创建的集合中不包含的值。
1 | const differenceBy = (a, b, fn) => { |
differenceWith
过滤掉数组中比较函数不返回true
的所有值。
使用Array.prototype.filter()
和Array.prototype.findindex()
查找适当的值。
1 | const differenceWith = (arr, val, comp) => arr.filter(a => val.findIndex(b => comp(a, b)) === -1); |
drop
返回一个从左边移除n个元素后的新数组。
使用Array.prototype.slice()
从左侧移除指定数量的元素。
1 | const drop = (arr, n = 1) => arr.slice(n); |
dropRight
返回一个从右边移除n个元素后的新数组。
使用Array.prototype.slice()
从右侧移除指定数量的元素。
1 | const drop = (arr, n = 1) => arr.slice(0, -n); |
dropRightWhile
从数组末尾移除元素,直到传递的函数返回true。返回数组中的剩余元素。
使用Array.protototype.slice()
循环数组,直到函数返回值为true
。返回剩余元素。
1 | const dropRightWhile = (arr, func) => { |
dropWhile
从数组开头移除元素,直到传递的函数返回true。返回数组中的剩余元素。
循环数组,使用Array.prototype.slice()
删除数组的第一个元素,直到函数返回值为true
。返回剩余元素。
1 | const dropWhile = (arr, func) => { |
everyNth
返回数组中顺序为nth倍数的元素。
使用Array.prototype.filter()
创建一个新数组,该数组包含给定数组中顺序为nth倍数的元素。
1 | const everyNth = (arr, nth) => arr.filter((e, i) => i % nth === nth - 1); |
filterNonUnique
过滤掉数组中的非唯一值。
使用Array.prototype.filter()
创建包含唯一值的数组。
1 | const filterNonUnique = arr => arr.filter(i => arr.indexOf(i) === arr.lastIndexOf(i)); |
filterNonUniqueBy
基于提供的比较器函数过滤掉数组中的非唯一值。
基于比较器函数fn
,对只包含唯一值的数组使用Array.prototype.filter()
和Array. prototype.every()
。比较器函数接受四个参数:两个被比较元素的值及其索引。
1 | const filterNonUniqueBy = (arr, fn) => |
findLast
返回调用所给函数返回真值的最后一个元素。
使用Array.prototype.filter()
过滤fn
返回假值的元素,使用Array.prototype.pop()
获取最后一个元素。
1 | const findLast = (arr, fn) => arr.filter(fn).pop(); |
findLastIndex
返回调用所给函数返回真值的最后一个元素的索引。
使用Array.prototype.map()
将每个元素与其索引和值映射到一个数组。使用Array.prototype.filter()
过滤fn
返回假值的元素,使用Array.prototype.pop()
获取最后一个元素。
1 | const findLastIndex = (arr, fn) => |
flatten
将数组展平到指定的深度。
使用递归,对于每一深度级别,深度递减1。使用Array.prototype.reduce()
和Array.prototype.concat()
合并元素或数组。一般情况下,如果深度等于1则停止递归。省略第二个参数,depth
仅展平到深度1 (单个展平)。
1 | // 理解起来有点困难 |
forEachRight
从数组的最后一个元素开始,为每个数组元素执行给定的函数。
使用Array.protototype.slice(0)
克隆给定的数组,使用Array.protototype.reverse()
反转数组,使用Array.protototype.foreach()
循环反向数组。
1 | const forEachRight = (arr, callback) => |
groupBy
根据给定函数对数组元素进行分组。
使用Array.prototype.map()
对数组元素调用到函数或属性。使用Array.protototype .reduce()
创建一个对象,其中的键是根据前面结果生成的。
1 | const groupBy = (arr, fn) => |
head
返回数组的第一个元素。
使用arr[0]
返回数组的第一个元素。
1 | const head = arr => arr[0]; |
indexOfAll
返回数组中val
出现的所有索引。如果val
从未出现,返回[]
。
使用Array.prototype.reduce()
循环元素并存储匹配元素的索引。返回索引数组。
1 | const indexOfAll = (arr, val) => arr.reduce((acc, el, i) => (el === val ? [...acc, i] : acc), []); |
initial
返回数组除了最后一个以外的所有元素。
使用arr.slice(0, -1)
来返回除最后一个元素以外的所有元素。
1 | const initial = arr => arr.slice(0, -1); |
initialize2DArray
生成指定行列和值的二维数组。
使用Array.prototype.map()
生成h行长度为w并填入值的数组。如果没有给定值,则默认为null
。
1 | const initialize2DArray = (w, h, val = null) => |
initializeArrayWithRange
初始化一个数组,该数组包含指定范围内的数字,并且按照指定步长递增。
使用Array.from()
创建所需长度的数组(结束-开始+1)/步长,并在给定范围内用所需值填充数组。可以省略开始值默认是0。也可以省略步长来使用默认值1。
1 | const initializeArrayWithRange = (end, start = 0, step = 1) => |
initializeArrayWithRangeRight
初始化一个数组,该数组包含指定范围内的数字(反向),并且按照指定步长递减。
使用Array.from(Math.ceil((end+1-start)/step))
创建所需长度的数组(长度等于(结束-开始)/步长或(结束+1-开始)/步长 (包含结束)),并在给定范围内用所需值填充数组。可以省略开始值默认是0。也可以省略步长来使用默认值1。
1 | const initializeArrayWithRangeRight = (end, start = 0, step = 1) => |
initializeArrayWithValues
用指定的值初始化并填充数组。
使用Array(n)
创建所需长度的数组,用fill(v)
根据所需值填充数组(v)。你可以省略val
来使用默认值0。
1 | const initializeArrayWithValues = (n, val = 0) => Array(n).fill(val); |
initializeNDArray
创建具有给定值的n维数组。
使用递归。用Array.prototype.map()
生成行数组,其中每一行都是使用initializendaray
初始化的新数组。
1 | const initializeNDArray = (val, ...args) => |
intersection
返回两个数组中都存在的元素数组。
从b
创建一个集合,然后在a
上使用Array.prototype.filter()
来只保留b
中包含的值。
1 | const intersection = (a, b) => { |
intersectionBy
将给定的函数应用于两个数组中的每个数组元素后,返回执行函数后第一个数组和第二个数组中相同的值。
b
中的所有元素执行fn
后创建一个集合,然后在a
上使用Array.prototype.filter()
来保留将执行fn
后结果在b中的元素。
1 | const intersectionBy = (a, b, fn) => { |
intersectionWith
使用给定的函数返回两个数组中都通过的元素数组。
使用Array.prototype.filter()
和Array.prototype.findindex()
与所提供的函数结合使用来确定公共值。
1 | const intersectionWith = (a, b, comp) => a.filter(x => b.findIndex(y => comp(x, y)) !== -1); |
isSorted
如果数组按升序排序,则返回1;如果数组按降序排序,则返回-1;如果数组未排序,则返回0。
计算前两个元素的排序方向。使用Object.entries()
循环数组元素并成对比较它们。如果方向改变,返回0;如果到达最后一个元素,返回排序方向。
1 | const isSorted = arr => { |
join
将数组中的所有元素连接成一个字符串并返回该字符串。使用起始分隔符和末端分隔符。
使用Array.prototype.reduce()
将元素组合成一个字符串。省略第二个参数separator
时,将使用,
作为默认分隔符。省略第三个参数end
时,默认情况下使用与separator
相同的值分隔。
1 | const join = (arr, separator = ',', end = separator) => |
JSONtoCSV
将对象数组转换为仅包含指定columns
的逗号分隔值(CSV)字符串。
使用Array.prototype.join(分隔符)
将columns
中的所有名称组合起来,创建第一行。使用Array.prototype.map()
和Array.prototype.reduce()
为每个对象创建一行,用空字符串替换不存在的值,只映射columns
中的值。使用Array.prototype.join('\n')
将所有行组合成一个字符串。省略第三个参数delimiter
,将会使用默认分隔符,
。
1 | const JSONtoCSV = (arr, columns, delimiter = ',') => |
last
返回数组中最后一个元素。
使用arr.length - 1
计算给定数组的最后一个元素的索引并返回它。
1 | const last = arr => arr[arr.length - 1]; |
longestItem
获取任意数量的可迭代对象或具有length属性的对象,并返回最长的对象。如果多个对象具有相同的长度,则将返回第一个对象。如果未提供参数,则返回undefined
。
使用Array.prototype.reduce()
,比较对象的长度以找到最长的对象。
1 | const longestItem = (...vals) => vals.reduce((a, x) => (x.length > a.length ? x : a)); |
mapObject
使用函数将数组的值映射到对象,其中键值对使用原始值作为键和计算后的映射值。
使用匿名内部函数声明未定义的内存空间,使用闭包存储返回值。使用一个新数组存储数组,新数组包含函数在传入数组上的映射,并使用逗号运算符返回第二步,而无需从一个上下文移动到另一个上下文(由于闭包和操作顺序)。
1 | const mapObject = (arr, fn) => |
maxN
从提供的数组中返回n个最大的元素。如果n大于或等于提供的数组长度,则返回原始数组(按降序排序)。
将Array.prototype.sort()
与扩展运算符(...
)结合使用浅拷贝数组并按降序排序。使用Array.prototype.slice()
获取指定数量的元素。省略第二个参数n
,得到只有一个元素的数组。
1 | const maxN = (arr, n = 1) => [...arr].sort((a, b) => b - a).slice(0, n); |
minN
从提供的数组中返回n个最小的元素。如果n大于或等于提供的数组长度,则返回原始数组(按升序排序)。
将Array.prototype.sort()
与扩展运算符(...
)结合使用浅拷贝数组并按升序排序。使用Array.prototype.slice()
获取指定数量的元素。省略第二个参数n
,得到只有一个元素的数组。
1 | const minN = (arr, n = 1) => [...arr].sort((a, b) => a - b).slice(0, n); |
none
如果集合中的所有元素执行给定的函数后都返回false,则返回true,否则返回false。
使用Array.prototype.some()
测试集合中的任何元素是否基于fn
返回true
。省略第二个参数fn
,将使用Boolean
作为默认值。
1 | const none = (arr, fn = Boolean) => !arr.some(fn); |
nthElement
返回数组的第n个元素。
使用Array.prototype.slice()
首先获得包含第n个元素的数组。如果索引超出范围,则返回undefined
。省略第二个参数n
,取数组的第一个元素。
1 | onst nthElement = (arr, n = 0) => (n === -1 ? arr.slice(n) : arr.slice(n, n + 1))[0]; |
offset
将指定数量的元素移动到数组的末尾。
使用两次Array.prototype.slice()
获得指定索引之后的元素和指定索引之前的元素。使用扩展运算符(...
)将两者组合成一个数组。如果offset
为负数,则元素将从尾部移动到头部。
1 | const offset = (arr, offset) => [...arr.slice(offset), ...arr.slice(0, offset)]; |
partition
根据每个元素执行函数后返回的布尔值,将元素分成两类数组。
使用Array.prototype.reduce()
创建一个由两个数组组成的数组。使用Array.prototype.push()
将fn
返回true
的元素添加到第一个数组,将fn
返回false
的元素添加到第二个数组。
1 | const partition = (arr, fn) => |
permutations
警告:这个函数的执行时间随着数组元素的增加呈指数增长。当浏览器试图计算所有不同的组合时,超过8到10个条目都会导致浏览器挂起。
生成数组元素的所有组合(包含重复元素)。
使用递归。对给定数组中进行元素遍历,为剩余元素创建所有的组合。使用Array.prototype.map()
将该元素与剩余部分排列组合起来,然后使用Array.prototype.reduce()
将所有排列组合成一个数组。一般情况是数组长度为2或1。
1 | const permutations = arr => { |
pull
变异原数组以过滤掉指定的值。
使用Array.prototype.filter()
和Array.prototype.include()
提取不需要的值。使用Array.protototype.length = 0
将将数组的长度重置为零来对数组中传递的值进行变异,并使用Array.prototype.push()
重新填充该值。
(对于不改变原始数组的代码片段,请参见without
)
1 | const pull = (arr, ...args) => { |
pullAtIndex
变异原数组以筛选出指定索引处的值。
使用Array.prototype.filter()
和Array.prototype.include()
提取不需要的值。使用Array.protototype.length = 0
将数组的长度重置为零来对数组中传递的值进行变异,并使用Array.prototype.push()
重新填充该值。使用Array.prototype.push()
来跟踪所提取的值。
1 | const pullAtIndex = (arr, pullArr) => { |
pullAtValue
变异原数组以过滤掉指定的值。返回删除的元素。
使用Array.prototype.filter()
和Array.prototype.include()
提取不需要的值。使用Array.protototype.length = 0
将数组的长度重置为零来对数组中传递的值进行变异,并使用Array.prototype.push()
重新填充该值。使用Array.prototype.push()
来跟踪所提取的值。
1 | const pullAtValue = (arr, pullArr) => { |
pullBy
基于给定的迭代函数,对原始数组进行变异以过滤掉指定的值。
检查函数中是否提供了最后一个参数。使用Array.prototype.map()
将迭代函数fn
应用于所有数组元素。使用Array.prototype.filter()
和Array.prototype.include()
提取不需要的值。使用Array.protototype.length = 0
将数组的长度重置为零来对数组中传递的值进行变异,并使用Array.prototype.push()
重新填充该值。
1 | const pullBy = (arr, ...args) => { |
reducedFilter
基于条件过滤对象数组,同时过滤掉未指定的键。
使用Array.prototype.filter()
根据函数fn
过滤数组,返回满足条件的对象。在过滤后的数组上,使用Array.prototype.map()
返回新对象,使用Array.prototype.reduce()
过滤掉未作为键参数提供的键。
1 | const reducedFilter = (data, keys, fn) => |
reduceSuccessive
对累加器和数组中的每个元素应用一个函数(从左到右),返回一个值变大的数组。
使用Array.prototype.reduce()
将给定的函数应用于数组,存储每个新的结果。
1 | const reduceSuccessive = (arr, fn, acc) => |
reduceWhich
应用提供的函数设置比较规则后,返回数组的最小值/最大值。
将Array.prototype.reduce()
与comparator
函数结合使用,在数组中取得对应的元素。可以省略第二个参数,使用返回数组中最小元素作为默认参数。
1 | // 简直精髓 |
reject
接收函数和数组,使用Array.prototype.Filter()
,但仅在pred(x) = false
时保留x
。
1 | const reject = (pred, array) => array.filter((...args) => !pred(...args)); |
remove
从数组中移除给定函数返回false的元素。
使用Array.prototype.filter()
查找返回真值的数组元素,使用Array.prototype.splice()
删除元素。函数是用三个参数(值、索引、数组)调用的。
1 | const remove = (arr, func) => |
sample
从数组中返回随机元素
使用Math.random()
生成一个随机数,并乘上数组长度,然后使用Math.floor()
向下取整。这个方法也适用于字符串。
1 | const sample = arr => arr[Math.floor(Math.random() * arr.length)]; |
sampleSize
从数组中以唯一键获取n个随机元素,直到数组结束。
使用Fisher-Yates算法洗牌数组。使用Array.prototype.slice()
获得前n
个元素。省略第二个参数n
,从数组中获取第一个元素。
1 | const sampleSize = ([...arr], n = 1) => { |
shank
和Array.prototype.splice()
功能相同,但是返回一个新的数组,而不是改变原始数组。
在移除现有元素/添加新元素后,使用Array.prototype.slice()
和Array.prototype .concat()
获得包含新内容的新数组。省略第二个参数index
,则从0
开始。省略第三个参数DelCount
,不删除元素。省略第四个参数元素,不添加新元素。
1 | const shank = (arr, index = 0, delCount = 0, ...elements) => |
shuffle
随机排列数组值的顺序,返回一个新数组。
使用Fisher-Yates算法对数组元素重新排序。
1 | const shuffle = ([...arr]) => { |
similarity
返回出现在两个数组中的元素数组。
使用Array.prototype.filter()
过滤非公共值,这些值是由Array.prototype.include()
确定的。
1 | const similarity = (arr, values) => arr.filter(v => values.includes(v)); |
sortedIndex
返回将值插入数组后仍保持其排序顺序的索引。
检查数组是否按降序排序。使用Array.prototype.findIndex()
找到元素应该插入的索引。
1 | const sortedIndex = (arr, n) => { |
sortedIndexBy
基于提供的函数,返回将值插入数组后仍保持其排序顺序的索引。
检查数组是否按降序排序。根据函数fn
,使用Array.prototype.findIndex()
找到元素应该插入的适当索引。
1 | const sortedIndexBy = (arr, n, fn) => { |
sortedLastIndex
返回最后索引,在该索引处,值插入数组保持其排序顺序。
检查数组是否按降序排序。使用Array.prototype.reverse()
和Array.prototype.findIndex()
找到元素应该插入的最后一个索引。
1 | const sortedLastIndex = (arr, n) => { |
sortedLastIndexBy
基于提供的函数,返回当值插入数组后保持其排序顺序的最后索引。
检查数组是否按降序排序。使用Array.prototype.map()
将函数应用于数组的所有元素。使用Array.prototype.reverse()
和Array.prototype.findIndex()
根据提供的函数,找到元素应该插入的最后一个索引。
1 | const sortedLastIndexBy = (arr, n, fn) => { |