原文链接:yazeedb.com/posts/10-mo…
原作者:Yazeed Bzadough
翻译者:发呆小贤
这次,带上单元测试
之前,我写了约10个使用reduce实现的工具函数。它广受好评,当我完成的时候,我对这个伟大的多功能工具有了更深的欣赏。为什么不再来10个呢?
这些函数其中很多是由优秀的库 Lodash 和 Ramda 所启发。我还编写了单元测试以确保行为正确。您可以在 Github仓库 上看到所有内容。
1. pipe
参数
...functions
- 任意数量的函数
描述
从左到右执行函数组合。管道的第一个参数用作初始值,并在通过每个函数时进行转换。
实现
const pipe = (...functions) => (initialValue) =>
functions.reduce((value, fn) => fn(value), initialValue);
用例
const mathSequence = pipe(
(x) => x * 2,
(x) => x - 1,
(x) => x * 3
);
mathSequence(1); // 3
mathSequence(2); // 9
mathSequence(3); // 15
有关更多详细的信息,我在 这里 写了一篇关于 pipe
的文章。
2. compose
参数
...functions
- 任意数量的函数
描述
从右到左执行函数组合。管道的第一个参数用作初始值,并在通过每个函数时进行转换。
工作原理和 pipe
相似,但方向相反。
实现
const compose = (...functions) => (initialValue) =>
functions.reduceRight((value, fn) => fn(value), initialValue);
用例
const mathSequence = compose(
(x) => x * 2,
(x) => x - 1,
(x) => x * 3
);
mathSequence(1); // 4
mathSequence(2); // 10
mathSequence(3); // 16
有关更多详细的信息,我在 这里 写了一篇关于 compose
的文章。
3. zip
参数
list1
- 列表1list2
- 列表2
描述
通过索引对两个列表中的元素进行配对。如果两个列表长度不相等,则使用较短列表的长度。
实现
const zip = (list1, list2) => {
const sourceList = list1.length > list2.length ? list2 : list1;
return sourceList.reduce((acc, _, index) => {
const value1 = list1[index];
const value2 = list2[index];
acc.push([value1, value2]);
return acc;
}, []);
};
用例
zip([1, 3], [2, 4]); // [[1, 2], [3, 4]]
zip([1, 3, 5], [2, 4]); // [[1, 2], [3, 4]]
zip([1, 3], [2, 4, 5]); // [[1, 2], [3, 4]]
zip(['Decode', 'secret'], ['this', 'message!']);
// [['Decode', 'this'], ['secret', 'message!']]
4. intersperse
参数
separator
- 要插入的元素list
- 列表
描述
在列表的每个元素之间插入分隔符。
实现
const intersperse = (separator, list) =>
list.reduce((acc, value, index) => {
if (index === list.length - 1) {
acc.push(value);
} else {
acc.push(value, separator);
}
return acc;
}, []);
用例
intersperse('Batman', [1, 2, 3, 4, 5, 6]);
// [1, 'Batman', 2, 'Batman', 3, 'Batman', 4, 'Batman', 5, 'Batman', 6]
intersperse('Batman', []);
// []
5. insert
参数
index
- 插入元素的索引newItem
- 要插入的新元素list
- 列表
描述
在给定的索引处插入一个元素。如果索引太大,则将元素插入列表的末尾。
实现
const insert = (index, newItem, list) => {
if (index > list.length - 1) {
return [...list, newItem];
}
return list.reduce((acc, value, sourceArrayIndex) => {
if (index === sourceArrayIndex) {
acc.push(newItem, value);
} else {
acc.push(value);
}
return acc;
}, []);
};
用例
insert(0, 'Batman', [1, 2, 3]);
// ['Batman', 1, 2, 3]
insert(1, 'Batman', [1, 2, 3]);
// [1, 'Batman', 2, 3]
insert(2, ['Batman'], [1, 2, 3]);
// [1, 2, ['Batman'], 3]
insert(10, ['Batman'], [1, 2, 3]);
// [1, 2, 3, ['Batman']]
6. flatten
参数
list
- 列表
描述
将列表按一级展平。
实现
const flatten = (list) => list.reduce((acc, value) => acc.concat(value), []);
用例
flatten([[1, 2], [3, 4]]);
// [1, 2, 3, 4]
flatten([[1, 2], [[3, 4]]]);
// [1, 2, [3, 4]]
flatten([[[1, 2]], [3, 4]]);
// [[1, 2], 3, 4]
flatten([[[1, 2], [3, 4]]]);
// [[1, 2], [3, 4]]
7. flatMap
参数
mappingFunction
- 每一项要运行的函数list
- 列表
描述
根据给定的函数映射每个列表项,然后展平结果。
实现
// Kind of cheating, because we already implemented flatten 😉
// 有点作弊,因为我们已经实现了flatten
const flatMap = (mappingFunction, list) => flatten(list.map(mappingFunction));
用例
flatMap((n) => [n * 2], [1, 2, 3, 4]);
// [2, 4, 6, 8]
flatMap((n) => [n, n], [1, 2, 3, 4]);
// [1, 1, 2, 2, 3, 3, 4, 4]
flatMap((s) => s.split(' '), ['flatMap', 'should be', 'mapFlat']);
// ['flatMap', 'should', 'be', 'mapFlat']
8. includes
参数
item
- 要检查的元素list
- 列表
描述
检查列表是否包含给定的列表元素。如果找到元素,则返回 true
。否则返回 false
。
实现
const includes = (item, list) =>
list.reduce((isIncluded, value) => isIncluded || item === value, false);
用例
includes(3, [1, 2, 3]); // true
includes(3, [1, 2]); // false
includes(0, []); // false
9. compact
参数
list
- 列表
描述
从列表中删除“假”值。
实现
const compact = (list) =>
list.reduce((acc, value) => {
if (value) {
acc.push(value);
}
return acc;
}, []);
用例
compact([0, null, 1, undefined, 2, '', 3, false, 4, NaN]);
// [1, 2, 3, 4]
10. arrayIntoObject
参数
key
- 用作新对象键的字符串list
- 列表
描述
使用给定键作为新对象的键,将数组转换为对象。
实现
const arrayIntoObject = (key, list) =>
list.reduce((acc, obj) => {
const value = obj[key];
acc[value] = obj;
return acc;
}, {});
用例
const users = [
{ username: 'JX01', status: 'offline' },
{ username: 'yazeedBee', status: 'online' }
];
arrayIntoObject('username', users);
/*
{
JX01: {
username: 'JX01',
status: 'offline'
},
yazeedBee: { username: 'yazeedBee', status: 'online' }
}
*/
arrayIntoObject('status', users);
/*
{
offline: {
username: 'JX01',
status: 'offline'
},
online: { username: 'yazeedBee', status: 'online' }
}
*/