本文翻译自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) => { |
stableSort
对数组执行排序,当项目的值相同时,保留项目的初始索引。不改变原始数组,返回一个新数组。
使用Array.prototype.map()
将输入数组的每个元素与其对应的索引配对。使用Array.prototype.sort()
和compare
函数对数组进行排序,如果比较的项目相等,则保留它们的初始顺序。使用Array.prototype.map()
转换回初始数组。
1 | const stableSort = (arr, compare) => |
symmetricDifference
返回两个数组之间的不同的值,没有滤掉重复值。
每个数组创建一个Set
,然后在每个数组上使用Array.prototype.filter()
来保留另一个数组中不包含的值。
1 | const symmetricDifference = (a, b) => { |
symmetricDifferenceBy
将给定的函数应用于两个数组的每个元素后,返回两个数组之间不同的值。
每个数组元素执行fn
后创建一个集合,然后在每个元素上使用Array.prototype.filter()
来只保留另一个元素中不包含的值。
1 | const symmetricDifferenceBy = (a, b, fn) => { |
symmetricDifferenceWith
使用提供的函数作为比较器,返回两个数组之间的不同的值。
使用Array.prototype.filter()
和Array.prototype.findIndex()
查找适当的值。
1 | const symmetricDifferenceWith = (arr, val, comp) => [ |
tail
返回数组中除第一个元素以外的所有元素。
如果数组长度大于1,则返回Array.prototype.slice(1)
,否则返回整个数组。
1 | const tail = arr => (arr.length > 1 ? arr.slice(1) : arr); |
take
返回从开头移除n个元素后的数组。
使用Array.prototype.slice()
返回第n
个元素后的元素浅拷贝。
1 | const take = (arr, n = 1) => arr.slice(0, n); |
takeRight
返回从末尾数n个元素后的数组。
使用Array.prototype.slice()
返回从末尾数n
个元素后的元素浅拷贝。
1 | const takeRight = (arr, n = 1) => arr.slice(arr.length - n, arr.length); |
takeRightWhile
从数组末尾移除元素,直到传递的函数返回true
。返回移除的元素。
当函数返回false
值时,使用Array.prototype.reduceRight()
循环遍历数组并累积元素。
1 | const takeRightWhile = (arr, func) => |
takeWhile
正向移除数组中的元素,直到传递的函数返回true
。返回移除的元素。
使用for...of
循环数组直到函数返回值为true
。使用Array.prototype.slice()
返回移除的元素。
1 | const takeWhile = (arr, func) => { |
toHash
将给定的类数组转化为哈希表(键控数据存储)。
给定一个可迭代的或类似数组的结构,在提供的对象上调用Array.prototype.reduce.call ()
,跨过它并返回一个对象,该对象由引用值键入。
1 | const toHash = (object, key) => |
union
返回两个数组中不重复的元素。
用a
和b
创建一个Set
,并转换为数组。
1 | const union = (a, b) => Array.from(new Set([...a, ...b])); |
unionBy
将给定的函数应用于两个数组中的每个数组元素后,返回两个数组中不重复的元素。
通过将fn
应用于a
的所有值来创建Set
。在执行fn
后,从a和b中的所有元素创建一个集合,这些元素的值与先前创建的集合中的值不匹配。返回转换为数组的最后一个集合。
1 | const unionBy = (a, b, fn) => { |
unionWith
使用提供的比较器函数,返回两个数组中不重复的元素。
创建一个Set
,其中包含比较器在a中找不到匹配项的所有a值和b值,使用Array.prototype.findIndex()
1 | const unionWith = (a, b, comp) => |
uniqueElements
返回数组的所有唯一值。
使用ES6Set
和...rest
运算符丢弃所有重复的值。
1 | const uniqueElements = arr => [...new Set(arr)]; |
uniqueElementsBy
基于提供的比较器函数,返回数组的所有唯一值。
使用Array.prototype.reduce()
和Array.prototype.some()
,根据比较器函数fn
,返回满足条件的第一次出现的元素。比较器函数有两个参数:正在比较的两个元素的值。
1 | const uniqueElementsBy = (arr, fn) => |
uniqueElementsByRight
基于提供的比较器函数,返回数组的所有唯一值。
使用Array.prototype.reduceRight()
和Array.prototype.some()
,根据比较器函数fn
,返回满足条件的第一次出现的元素。比较器函数有两个参数:正在比较的两个元素的值。
1 | const uniqueElementsByRight = (arr, fn) => |
uniqueSymmetricDifference
返回两个数组之间不重复的值。
在每个数组上使用Array.prototype.filter()
和Array.prototype.includes()
来删除另一个数组中包含的值,然后根据结果创建一个集合,删除重复的值。
1 | const uniqueSymmetricDifference = (a, b) => [ |
unzip
创建二维数组,将zip生成的数组中的元素取消分组。
使用Math.max.apply()
得到最长的数组长度,Array.prototype.map()
生成数组。使用Array.prototype.reduce()
和Array.prototype.forEach()
将分组值映射到单个数组。
1 | const unzip = arr => |
unzipWith
创建一个元素数组,将zip生成的数组中的元素取消分组,并应用提供的函数。
使用Math.max.apply()
得到最长的数组长度,Array.prototype.map()
生成数组。使用Array.prototype.reduce()
和Array.prototype.forEach()
将分组值映射到单个数组。使用Array.prototype.map()
和扩展运算符(...
)将fn
应用于每个单独的元素数组。
1 | const unzipWith = (arr, fn) => |
without
筛选出数组中不是指定值的元素。
使用Array.prototype.filter()
创建一个数组,排除(使用!Array.includes()
方法)所有给定值。
(对于改变原始数组的代码片段,请参见pull)
1 | const without = (arr, ...args) => arr.filter(v => !args.includes(v)); |
xProd
通过从数组中创建每个可能的对,在提供的两个数组中创建一个新数组。
使用Array.prototype.reduce()
,Array.prototype.map()
和Array.prototype.concat()
从两个数组的元素中产生每一个组合,并将它们保存在新数组中。
1 | const xProd = (a, b) => a.reduce((acc, x) => acc.concat(b.map(y => [x, y])), []); |
zip
创建元素数组,根据原始数组中的位置分组。
使用Math.max.apply()
获取传入数组的最大长度。创建一个长度为最大长度的数组,并使用Array.from()
和映射函数创建一个分组数组。如果参数数组的长度不同,则在没值的地方使用undefined
。
1 | const zip = (...arrays) => { |
zipObject
给定有效的属性数组和值数组,返回一个将属性与值相关联的对象。
由于对象可以有未定义的值,但不能有未定义的属性,属性数组使用Array. prototype.reduce()
来决定结果对象的结构。
1 | const zipObject = (props, values) => |
zipWith
创建一个数组,根据原始数组中的位置进行分组,并使用函数作为最后一个值来指定分组值的组合方式。
检查提供的最后一个参数是否是函数。使用Math.max()
获取参数中数组最大长度。创建一个长度为最大值的数组,并使用Array.from()
和映射函数创建一个分组元素数组。如果参数数组的长度不同,则在无值的地方使用undefined
。用每个组的元素调用该函数(...group)
。
1 | const zipWith = (...array) => { |
Browser
arrayToHtmlList
将给定数组元素转换为<li>
标签,并将它们追加到给定id的列表中。
使用Array.prototype.map()
、document.querySelector()
和匿名闭包函数创建html标记。
1 | const arrayToHtmlList = (arr, listID) => |
bottomVisible
如果页面到达底部,则返回true
,否则返回false
。
使用scrollY
、scrollHeight
和clientHeight
来确定页面是否到达底部。
1 | const bottomVisible = () => |
copyToClipboard
⚠️注意:通过使用新的剪贴板异步API,同样的功能可以更容易地实现,这个API仍然是实验性的,但是应该在将来使用,而不是这个片段。点击了解更多信息。
将字符串复制到剪贴板。仅当用户有操作才可用(例如,在点击事件中)。
创建一个<textarea>
,用提供的数据填充它,并将其添加到HTML文档中。使用Selection.getRangeAt()
存储所选范围(如果有)。使用document.execCommand('copy')
复制到剪贴板。之后从HTML文档中删除元素。最后,使用Selection().addRange()
以恢复原始选定范围(如果有)。
1 | const copyToClipboard = str => { |
counter
为指定的选择器创建具有指定范围、步长和持续时间的计数器。
检查step
正负是否正确,并相应地进行更改。将setInterval()
与Math.abs()
、Math.floor()
结合使用,计算每次新文本绘制的时间。使用document.querySelector().innerHTML
来更新元素的值。省略第四个参数step
,使用默认值1
。省略第五个参数duration
,使用2000
毫秒的默认持续时间。
1 | const counter = (selector, start, end, step = 1, duration = 2000) => { |
createElement
根据字符串创建元素(不将其添加到文档)。如果给定字符串包含多个元素,则返回第一个元素。
使用document.createElement()
创建一个新元素。将它的innerHTML
设置为参数提供的字符串。使用ParentNode.firstElementChild
返回字符串的元素版本。
1 | const createElement = str => { |
createEventHub
使用emit、on和off方法创建发布/订阅事件中心。
使用Object.create(null)
创建一个不从Object.prototype
继承属性的空集线器对象。对于emit,请根据事件参数解析处理程序数组,然后通过将数据作为参数传入,使用Array.prototype.forEach ( )运行每个处理程序数组。对于on,如果事件尚不存在,请为其创建一个数组,然后使用Array.prototype.push ( )将处理程序添加到数组中。对于off,使用数组. prototype.findIndex ( )在事件数组中查找处理程序的索引,并使用数组. prototype.splice ( )将其移除。
1 | const createEventHub = () => ({ |
currentURL
返回当前网址。
使用window.location.href
获取当前网址。
1 | const currentURL = () => window.location.href; |
detectDeviceType
检测网站是在移动设备中打开还是在台式机/笔记本电脑中打开。
使用正则表达式匹配navigator.userAgent
属性,以确定设备是移动设备还是台式机/笔记本电脑。
1 | const detectDeviceType = () => |
elementContains
如果父元素包含子元素,则返回true
,否则返回false
。
检查父元素和子元素是否不同,使用parent.contains(child)
检查父元素是否包含子元素。
1 | const elementContains = (parent, child) => parent !== child && parent.contains(child); |
elementIsVisibleInViewport
如果指定的元素在视口中可见,则返回true
,否则返回false
。
使用Element.getBoundingClientRect()
和window.inner(Width|Height)
值来确定给定元素在视口中是否可见。省略第二个参数表示元素完全可见,或者指定true
来表示部分可见。
1 | const elementIsVisibleInViewport = (el, partiallyVisible = false) => { |
getImages
从元素中提取所有图像,并将它们放入数组中
使用Element.prototype.GetElementsBytagName()
获取所提供元素中的所有的<img>
元素,Array.prototype.map()
映射每个元素的src
属性,然后创建一个集合来消除重复并返回数组。
1 | const getImages = (el, includeDuplicates = false) => { |
getScrollPosition
返回当前页面的滚动位置。
如果有pageXOffset
和pageYOffset
则使用它们,否则使用scrollLeft
和scrollTop
。省略el
使用默认值window
。
1 | const getScrollPosition = (el = window) => ({ |
getStyle
返回指定元素的CSS规则值。
使用window.getComputedStyle()
获取指定元素的CSS规则值。
1 | const getStyle = (el, ruleName) => getComputedStyle(el)[ruleName]; |
hasClass
如果元素具有指定的类名,则返回true
,否则返回false
。
使用element.classList.contains()
检查该元素是否具有指定的类名。
1 | const hasClass = (el, className) => el.classList.contains(className); |
hashBrowser
使用SHA-256算法为传入值创建哈希值。返回一个Promise
。
使用SubtleCrypto接口为给定值创建哈希。
1 | const hashBrowser = val => |
hide
隐藏所有指定的元素。
使用NodeList.prototype.forEach()
对指定的每个元素应用display: none
。
1 | const hide = (...el) => [...el].forEach(e => (e.style.display = 'none')); |
httpsRedirect
如果页面当前是http协议,则将其重定向到https协议。另外,按下后退按钮并不会将它回到http协议页面,因为历史记录中网页已经被替换。
使用location.protocol
获取当前正在使用的协议。如果不是HTTPS,使用location.replace()
用页面的HTTPS版本替换现有页面。使用location.href
获取完整地址,用String.prototype.split()
将其拆分,并删除网址的协议部分。
1 | const httpsRedirect = () => { |
insertAfter
在指定元素的末尾插入一个HTML字符串。
使用参数为afterend
的el.insertAdjacentHTML()
解析htmlString
,并将其插入el
的末尾。
1 | const insertAfter = (el, htmlString) => el.insertAdjacentHTML('afterend', htmlString); |
insertBefore
在指定元素的开头插入一个HTML字符串。
使用参数为beforebegin
的el.insertAdjacentHTML()
解析htmlString
,并将其插入el
的末尾。
1 | const insertBefore = (el, htmlString) => el.insertAdjacentHTML('beforebegin', htmlString); |
isBrowserTabFocused
如果当前页面在浏览器页面选项卡为聚焦状态,则返回true
,否则返回false
。
使用Document.hidden
属性来检查页面在浏览器选项卡中是可见的还是隐藏的。
1 | const isBrowserTabFocused = () => !document.hidden; |
nodeListToArray
将NodeList
转换为数组。
在新数组中使用扩展运算符将NodeList
转换为数组。
1 | const nodeListToArray = nodeList => [...nodeList]; |
observeMutations
返回一个新的MutationObserver
,并为指定元素上的每次变化提供回调。
使用MutationObserver
观察给定元素的变化。使用Array.prototype.forEach()
对观察到的每次变化执行回调。省略第三个参数选项,使用默认选项(全部为true
)。
1 | const observeMutations = (element, callback, options) => { |
off
从元素中移除事件侦听器。
使用EventTarget.removeEventListener()
从元素中移除事件侦听器。省略第四个参数opts
默认false,或者根据添加事件侦听器时使用的选项决定。
1 | const off = (el, evt, fn, opts = false) => el.removeEventListener(evt, fn, opts); |
on
将事件侦听器添加到能够使用事件委托的元素中。
使用EventTarget.addEventListener()
将事件侦听器添加到元素中。如果options对象提供了target
属性,请确保事件目标与指定的目标匹配,然后通过提供正确的this
回调。返回对自定义委托器函数的引用,以便可以与off一起使用。省略opts
默认为非委托行为和事件冒泡。
1 | onst on = (el, evt, fn, opts = {}) => { |
onUserInputChange
每当用户输入类型改变(mouse
或touch
)时运行回调。根据输入设备启用/禁用代码非常有用。该过程是动态的,适用于混合设备(例如触摸屏笔记本电脑)。
使用两个事件监听器。最初认为mouse
输入,并将touchstart
事件侦听器绑定到文档。在touchstart
上,添加一个mousemove
事件侦听器,使用performance.now()
监听20毫秒内连续触发的两个mousemove
事件。在任何情况下,以输入类型作为参数运行回调。
1 | onst onUserInputChange = callback => { |
prefix
返回浏览器支持的CSS属性的前缀版本(如果需要)。
在前缀字符串数组上使用Array.prototype.findIndex()
来测试document.body
是否在其CSSStyleDeclaration
对象中定义了其中一个字符串,否则返回null
。使用String.prototype.charAt()
和String.prototype.toUpperCase()
将属性第一个字母大写,该属性将附加到前缀字符串数组上。
1 | const prefix = prop => { |
recordAnimationFrames
在每个动画帧上调用提供的回调。
使用递归。定义变量running
为true
,持续执行window.requestAnimationFrame()
,它调用所提供的回调。返回一个对象有start
和stop
方法,以便手动控制。省略第二个参数autoStart
,以便在调用函数时隐式调用start
方法。
1 | const recordAnimationFrames = (callback, autoStart = true) => { |
redirect
重定向到指定的网址。
使用window.location.href
或window.location.replace()
重定向到url
。传递第二个参数来模拟链接点击(true
-默认)或HTTP重定向(false
)。
1 | onst redirect = (url, asLink = true) => |
runAsync
通过使用Web Worker在单独的线程中运行函数,允许长时间运行的函数而不阻塞用户界面。
使用Blob
对象URL创建一个新的Worker
,其内容是所提供函数执行后的返回值。返回一个promise
,监听onmessage
和onerror
事件,解析从worker
返回的数据,或者抛出一个错误。
1 | const runAsync = fn => { |
scrollToTop
平滑滚动到页面顶部。
使用document.documentElement.ScrollTop
或document.body.scrollTop
获取到顶部的距离。使用window.requestAnimationFrame()
执行动画滚动。
1 | const scrollToTop = () => { |
setStyle
为指定元素设置CSS规则的值。
使用element.style
将指定元素的CSS规则值设置为val
。
1 | const setStyle = (el, ruleName, val) => (el.style[ruleName] = val); |
show
显示所有指定的元素。
使用扩展运算符(...
)和Array.prototype.forEach()
来清除指定的每个元素的display
属性。
1 | const show = (...el) => [...el].forEach(e => (e.style.display = '')); |
smoothScroll
将调用它的元素平滑滚动到浏览器窗口的可见区域。
使用.scrollIntoView
方法滚动元素。将{ behavior: 'smooth' }
传递给.scrollIntoView
,以便平滑滚动。
1 | const smoothScroll = element => |
toggleClass
切换元素的类。
使用element.classList.toggle()
为元素切换指定的类。
1 | const toggleClass = (el, className) => el.classList.toggle(className); |
triggerEvent
触发给定元素上的特定事件,可选传递自定义数据。
使用new CustomEvent()
按照指定的eventType
和详细信息创建事件。使用el.dispatchEvent()
在给定元素上触发新创建的事件。如果不想将自定义数据传递给触发事件,请省略第三个参数detail
。
1 | const triggerEvent = (el, eventType, detail) => |
UUIDGeneratorBrowser
在浏览器中生成UUID。
使用crypto API
生成UUID,并且符合RFC4122版本4。
1 | onst UUIDGeneratorBrowser = () => |
Date
dayOfYear
从Date
对象获取一年中的某一天的天数。
使用new Date()
和Date.prototype.getFullYear()
获取一年中的第一天作为Date
对象,将提供的date
中减去该日期,然后除以每天的毫秒得出结果。使用Math.floor()
将得到的天数向下取整为整数。
1 | const dayOfYear = date => |
formatDuration
返回给定毫秒数的正常可读格式。
将ms
除以对应的值,获得day
、hour
、minute
、second
和millisecond
。将Object.entries()
与Array.prototype.filter()
一起使用,只保留非零值。使用Array.prototype.map()
为每个值创建字符串。使用String.prototype.join(', ')
将这些值组合成一个字符串。
1 | const formatDuration = ms => { |
getColonTimeFromDate
从Date
对象返回HH:MM:SS
形式的字符串。
使用Date.prototype.ToomString()
和String.prototype.slice()
获取给定日期对象的HH:MM:SS
部分。
1 | const getColonTimeFromDate = date => date.toTimeString().slice(0, 8); |
getDaysDiffBetweenDates
返回两个日期之间的差值(以天为单位)。
计算两个日期对象之间的差值(以天为单位)。
1 | const getDaysDiffBetweenDates = (dateInitial, dateFinal) => |
getMeridiemSuffixOfInteger
将整数转换为字符串,根据其值添加am
或pm
。
使用取余运算符(%
)和条件检查将整数转换为带子午线后缀的字符串12小时格式。
1 | const getMeridiemSuffixOfInteger = num => |
isAfterDate
检查一个日期是否在另一个日期之后。
使用大于运算符(>
)检查第一个日期是否在第二个日期之后。
1 | const isAfterDate = (dateA, dateB) => dateA > dateB; |
isBeforeDate
检查一个日期是否在另一个日期之前。
使用小于运算符(<
)检查第一个日期是否在第二个日期之前。
1 | const isBeforeDate = (dateA, dateB) => dateA < dateB; |
isSameDate
检查一个日期是否与另一个日期相同。
使用Date.prototype.toISOString()
和严格的相等性检查(===
)来检查第一个日期是否与第二个日期相同。
1 | const isSameDate = (dateA, dateB) => dateA.toISOString() === dateB.toISOString(); |
maxDate
返回给定日期的最大值。
使用Math.max.apply()
查找最大的日期,使用new Date()
将其转换为Date
对象。
1 | const maxDate = (...dates) => new Date(Math.max.apply(null, ...dates)); |
minDate
返回给定日期的最小值。
使用Math.min.apply()
查找最小的日期,使用new Date()
将其转换为Date
对象。
1 | const minDate = (...dates) => new Date(Math.min.apply(null, ...dates)); |
tomorrow
返回明天日期的字符串表示。
使用new Date()
获取当前日期,将Date.getDate()
增加1,并使用Date.setDate()
将该值设置为结果。使用Date.prototype.toISOString()
返回yyyy-mm-dd
格式的字符串。
1 | const tomorrow = () => { |
Function
attempt
尝试使用提供的参数调用函数,返回结果或捕获的错误对象。
使用try...catch
块返回函数的结果或的错误。
1 | const attempt = (fn, ...args) => { |
bind
创建一个在给定上下文中调用fn的函数,可以选择在参数的开头添加任何附加的参数。
返回一个使用Function.prototype.apply()
将给定上下文应用于fn
的函数。使用Array.prototype.concat()
(译者注:实际是展开运算符)将附加的参数添加到提供的参数前。
1 | const bind = (fn, context, ...boundArgs) => (...args) => fn.apply(context, [...boundArgs, ...args]); |
bindKey
创建一个函数,该函数在对象的给定key
处调用方法,可以选择在参数的开头添加任何额外提供的参数。
返回一个使用Function.prototype.apply()
将context[fn]
绑定到context
的函数。使用扩展运算符(...
)将附加的参数添加到提供的参数前。
1 | const bindKey = (context, fn, ...boundArgs) => (...args) => |
chainAsync
异步函数链式调用。
遍历包含异步事件的函数数组,当每个异步事件完成时调用next。
1 | const chainAsync = fns => { |
checkProp
给定一个predicate
函数和一个prop
字符串,柯里化函数将传入object
的属性给predicate
调用。
调用obj
上的prop
,将其传递给提供的predicate
函数,并返回函数执行后的布尔值。
1 | const checkProp = (predicate, prop) => obj => !!predicate(obj[prop]); |
compose
从右向左的执行函数。
使用Array.prototype.reduce()
执行从右向左的函数组合。最后一个(最右边的)函数可以接受一个或多个参数;剩余的函数必须是一元的。
1 | const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args))); |
composeRight
从左向右的执行函数。
使用Array.prototype.reduce()
执行从左向右的函数组合。第一个(最右边的)函数可以接受一个或多个参数;剩余的函数必须是一元的。
1 | const composeRight = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args))); |
converge
接受收敛函数和分支函数列表,并返回每个分支函数执行传入参数的结果,分支函数的结果作为参数传递给收敛函数。
使用Array.prototype.map()和Function.prototype.apply()将每个函数应用于给定的参数。使用扩展运算符(…)用所有其他函数的结果调用coverger。
1 | const converge = (converger, fns) => (...args) => converger(...fns.map(fn => fn.apply(null, args))); |
curry
柯里化一个函数。
使用递归。如果提供的参数(args)数量足够,则调用传递的函数fn。否则,返回期望其余参数的curried函数fn。如果您想要获取一个接受可变参数数的函数(一个可变函数,例如Math.min()),您可以选择将参数数传递给第二个参数arity。
1 | const curry = (fn, arity = fn.length, ...args) => |
debounce
创建一个去抖函数,将给定的函数经过至少ms
毫秒延迟后才会被调用。
每次调用去抖函数时,先使用clearTimeout()
清除当前挂起的定时器id,并使用setTimeout()
方法创建一个新的定时器,该定时器将调用函数ms
毫秒后执行。使用Function.prototype.apply()
将上下文应用于函数,并提供必要的参数。省略第二个参数ms
,将超时设置为默认值0 ms。
1 | const debounce = (fn, ms = 0) => { |
defer
推迟调用函数,直到当前调用堆栈被清除。
使用超时为1毫秒的setTimeout()
方法向浏览器事件队列添加新事件,并允许渲染引擎完成其工作。使用跨页(…)运算符为函数提供任意数量的参数。
1 | const defer = (fn, ...args) => setTimeout(fn, 1, ...args); |
functionName
记录函数的名称。
使用console.debug()
和传入函数的name属性,将函数的名称输出到控制台的调试消息中。
1 | const functionName = fn => (console.debug(fn.name), fn); |
hz
返回一个函数每秒执行的次数。hz
是频率的单位,频率单位定义为每秒一个周期。
使用performance.now()
获取函数执行前后的毫秒差,以计算执行函数迭代次数所用的时间。通过将毫秒转换为秒并将它除以经过的时间,返回每秒的周期数。省略第二个参数iterations
,使用默认值100次迭代。
1 | const hz = (fn, iterations = 100) => { |
memoize
返回缓存函数。
通过实例化新的Map
对象来创建空缓存。返回一个函数,该函数通过首先检查函数对于该特定输入值的输出是否已经缓存,或者如果没有缓存,则存储并返回它,从而将单个参数提供给memoized函数。必须使用function关键字,以便在必要时允许memoized函数更改其上下文。通过将缓存设置为返回函数的属性,允许访问缓存。
1 | const memoize = fn => { |
negate
否定函数。
执行传入函数并应用not运算符(!
)。
1 | const negate = func => (...args) => !func(...args); |
once
确保函数只被调用一次。
使用闭包,定义一个标志called
,并在第一次调用函数时将其设置为true
,防止再次调用它。为了允许函数改变其上下文(例如在事件监听器中),必须使用function关键字,并且所提供的函数必须应用上下文。允许使用展开运算符为函数提供任意数量的参数。
1 | const once = fn => { |
partial
创建一个调用fn
的函数,该函数在其接收的参数前添加了partials
参数。
使用扩展运算符(...
)在fn的参数列表前添加新参数partials
。
1 | const partial = (fn, ...partials) => (...args) => fn(...partials, ...args); |
partialRight
创建一个调用fn
的函数,该函数在其接收的参数后添加了partials
参数。
使用扩展运算符(...
)在fn
的参数列表后添加新参数partials
。
1 | const partialRight = (fn, ...partials) => (...args) => fn(...args, ...partials); |
runPromisesInSeries
执行一串promise。
使用Array.prototype.reduce()创建一个promise链,其中每个promise在解析后返回给下一个promise。
sleep
延迟异步函数的执行。
通过将async
函数置于睡眠状态,延迟执行异步函数,返回一个Promise
。
1 | const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); |
throttle
创建一个节流函数,该函数每隔wait
毫秒调用一次所提供的函数。
使用setTimeout()
方法和clearTimeout()
来节流给定的方法fn
。使用Function.prototype.apply()
将上下文应用于函数,并提供必要的参数。使用Date.now()
来跟踪上次调用节流函数的时间。省略第二个参数wait
,将定时器设置为默认值0毫秒。
1 | const throttle = (fn, wait) => { |
times
迭代回调n次。
使用Function.call()
调用fn
n
次或者直到它返回false
。省略最后一个参数context
,将使用undefined
对象(或者非严格模式下的全局对象)。
1 | const times = (n, fn, context = undefined) => { |
uncurry
反柯里化至深度n。
返回一个可变参函数。对提供的参数使用Array.prototype.reduce()
调用函数的每个后续柯里化级别。如果提供的参数的长度小于n
,则抛出一个错误。否则,使用Array.prototype.slice(0,n)
用给定数量的参数调用fn。省略第二个参数n
,默认深度1。
1 | const uncurry = (fn, n = 1) => (...args) => { |
unfold
使用迭代函数和初始值构建数组。
使用while
循环和Array.prototype.push()
重复调用该函数,直到它返回false
。迭代器函数接受一个参数(seed
),并且必须始终返回一个包含两个元素([value
,nextSeed
)的数组或false
才能终止。
1 | const unfold = (fn, seed) => { |
when
根据传入的函数测试值x
。如果为true
,返回fn(x)
。否则,返回x
。
返回一个期望单个值x
的函数,该值根据pred
返回适当的值。
1 | const when = (pred, whenTrue) => x => (pred(x) ? whenTrue(x) : x); |
Math
approximatelyEqual
检查两个数字在误差范围是否大致相等。
使用Math.abs()
将两个数差值的绝对值与epsilon
(译者注:高数中的ε)进行比较。省略第三个参数epsilon
,使用默认值0.001
。
1 | const approximatelyEqual = (v1, v2, epsilon = 0.001) => Math.abs(v1 - v2) < epsilon; |
average
返回两个或多个数字的平均值。
使用Array.prototype.reduce()
将所有值添加到累加器中,用值0
初始化,除以数组长度。
1 | const average = (...nums) => nums.reduce((acc, val) => acc + val, 0) / nums.length; |
averageBy
使用提供的函数将每个元素映射到一个值后,返回数组的平均值。
使用Array.prototype.map()
将每个元素映射到由fn
返回的值,用Array.prototype.reduce()
将每个值添加到累加器中,并用0
初始化,之后除以数组的长度。
1 | const averageBy = (arr, fn) => |
binomialCoefficient
计算两个整数n
和k
的二项式系数。
使用Number.isNaN()
检查两个值中是否有一个是NaN
。检查k
的值,如果小于0
或大于n
返回0,如果等于0
或等于n
返回1,如果等于1
或等于n - 1
返回n
。检查n - k
是否小于k
,并相应地交换它们的值。从2
到k
循环并计算二项式系数。使用Math.round()
计算舍入误差。
1 | const binomialCoefficient = (n, k) => { |
clampNumber
在边界值a
和b
指定的包含范围内的更接近的num
。
如果num
落在该范围内,则返回num
。否则,返回范围内最近的数字。
1 | const clampNumber = (num, a, b) => Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b)); |
degreesToRads
将角度从角度转换为弧度。
使用Math.PI
和弧度公式将角度从度数转换为弧度。
1 | const degreesToRads = deg => (deg * Math.PI) / 180.0; |
digitize
将数字转换为数字数组。
使用扩展运算符(...
)来构建数组。使用Array.prototype.map()
和parseInt()
将每个值转换为整数。
1 | const digitize = n => [...`${n}`].map(i => parseInt(i)); // 还能这么展开 |
distance
返回两点之间的距离。
使用Math.hypot()
计算两点之间的欧几里德距离。
1 | const distance = (x0, y0, x1, y1) => Math.hypot(x1 - x0, y1 - y0); |
elo
使用Elo评分系统计算两个或更多对手之间的评分。它接受一个预评分数组,并返回一个后评分的数组。数组从最优表现者到最差表现者排序(赢家->输家)。
使用指数**
运算符和数学运算符计算预期分数(获胜机会)。计算每个对手的评分。循环评分,使用成对的方式计算每个玩家的Elo后评级。省略第二个参数,使用默认的KFactor
32。
1 | const elo = ([...ratings], kFactor = 32, selfRating) => { |
factorial
计算一个数的阶乘。
使用递归。如果n小于或等于1,返回1。否则,返回n的乘积和n - 1的阶乘。如果n是负数,则引发异常。
1 | const factorial = n => |
fibonacci
生成一个数组,包含n个项的斐波那契序列。
先创建指定长度的空数组,初始化前两个值(0
和1
)。使用Array.prototype.reduce()
将值添加到数组中,使用除前两个值之外的最后两个值的总和。
1 | const fibonacci = n => |
gcd
计算两个或多个数字/数组之间的最大公约数。
内部_gcd
函数使用了递归。当y
等于0
时返回x
。否则,返回y
和x%y
执行gcd结果。
1 | const gcd = (...arr) => { |