| name | functional-programming |
| description | 使用函数式编程工具(map、filter、reduce、group、omit、unique)进行数据转换和操作。构建可组合的、不可变的数据操作。 |
函数式编程技能
何时使用此技能
当你需要以下操作时使用此技能:
- 转换数据(map、filter、reduce)
- 按属性或条件分组 项目
- 从对象中移除属性
- 在数组中找到唯一项
- 将操作组合 成管道
- 使用不可变数据 模式
快速入门
import { groupBy } from '@x-oasis/group-by';
import { omit } from '@x-oasis/omit';
import { uniqueArrayObject } from '@x-oasis/unique-array-object';
import { eachArray } from '@x-oasis/each';
const users = [
{ id: 1, role: 'admin', name: 'John' },
{ id: 2, role: 'user', name: 'Jane' },
{ id: 3, role: 'admin', name: 'Bob' },
];
const byRole = groupBy(users, 'role');
const userWithoutId = omit(users[0], ['id']);
const uniqueRoles = uniqueArrayObject(
users.map(u => ({ role: u.role }))
);
eachArray(users, (user, index) => {
console.log(`${index}: ${user.name}`);
});
可用工具
| 函数 | 目的 | 用例 |
|---|
groupBy(array, key) | 按属性分组项目 | 分析、报告 |
omit(object, keys) | 移除属性 | 隐私、过滤 |
uniqueArrayObject(array) | 对象去重 | 去重 |
eachArray(array, fn) | 带索引迭代 | 处理 |
findLastIndex(array, fn) | 从末尾查找 | 反向搜索 |
模式 1:按分组
import { groupBy } from '@x-oasis/group-by';
const transactions = [
{ user: 'alice', amount: 100 },
{ user: 'bob', amount: 50 },
{ user: 'alice', amount: 75 },
];
const byUser = groupBy(transactions, 'user');
真实例子:汇总数据
import { groupBy } from '@x-oasis/group-by';
function summarizeSales(sales: Sale[]) {
const byProduct = groupBy(sales, 'product');
return Object.entries(byProduct).map(([product, items]) => ({
product,
total: items.reduce((sum, item) => sum + item.price, 0),
count: items.length,
average: items.reduce((sum, item) => sum + item.price, 0) / items.length,
}));
}
模式 2:对象属性过滤
import { omit } from '@x-oasis/omit';
const user = {
id: 1,
name: 'John',
email: 'john@example.com',
passwordHash: 'xxx',
apiKey: 'secret',
};
const safeUser = omit(user, ['passwordHash', 'apiKey']);
真实例子:API 响应清理
import { omit } from '@x-oasis/omit';
async function getUserData(userId: string) {
const user = await db.users.findById(userId);
return omit(user, [
'passwordHash',
'internalId',
'createdAt',
'lastModified'
]);
}
模式 3:唯一项
import { uniqueArrayObject } from '@x-oasis/unique-array-object';
const tags = [
{ name: 'javascript', count: 10 },
{ name: 'typescript', count: 5 },
{ name: 'javascript', count: 10 },
];
const uniqueTags = uniqueArrayObject(tags);
真实例子:搜索建议
import { uniqueArrayObject } from '@x-oasis/unique-array-object';
function getSuggestions(searchHistory: SearchEntry[]) {
const queries = searchHistory.map(entry => ({
query: entry.query,
timestamp: entry.timestamp
}));
return uniqueArrayObject(queries).slice(0, 10);
}
模式 4:函数管道
import { groupBy } from '@x-oasis/group-by';
import { omit } from '@x-oasis/omit';
function processUserData(users: User[]) {
const active = users.filter(u => u.isActive);
const mapped = active.map(u => ({
id: u.id,
displayName: u.name.toUpperCase(),
}));
const grouped = groupBy(mapped, 'displayName');
return Object.entries(grouped).map(([name, items]) => ({
displayName: name,
count: items.length,
users: items.map(u => omit(u, ['temp', 'debug'])),
}));
}
模式 5:使用分组的 Reduce
import { groupBy } from '@x-oasis/group-by';
const orders = [
{ customer: 'alice', amount: 100 },
{ customer: 'bob', amount: 50 },
{ customer: 'alice', amount: 75 },
{ customer: 'bob', amount: 200 },
];
const byCustomer = groupBy(orders, 'customer');
const stats = Object.entries(byCustomer).map(([customer, items]) => ({
customer,
total: items.reduce((sum, o) => sum + o.amount, 0),
average: items.reduce((sum, o) => sum + o.amount, 0) / items.length,
max: Math.max(...items.map(o => o.amount)),
min: Math.min(...items.map(o => o.amount)),
}));
模式 6:数据迁移/转换
import { omit } from '@x-oasis/omit';
import { groupBy } from '@x-oasis/group-by';
interface OldUser {
id: number;
firstName: string;
lastName: string;
internalRef?: string;
}
interface NewUser {
userId: number;
fullName: string;
}
function migrateUsers(oldUsers: OldUser[]): NewUser[] {
return oldUsers
.map(user => ({
userId: user.id,
fullName: `${user.firstName} ${user.lastName}`,
}))
.filter(user => user.fullName.length > 0);
}
function cleanupLegacyData(data: any) {
const legacyFields = ['deprecated_field', 'old_format', 'temp_data'];
return data.map(item => omit(item, legacyFields));
}
模式 7:带上下文迭代
import { eachArray } from '@x-oasis/each';
const items = ['apple', 'banana', 'cherry'];
eachArray(items, (item, index) => {
console.log(`${index + 1}. ${item}`);
});
真实例子:位置感知处理
import { eachArray } from '@x-oasis/each';
function formatList(items: string[], maxPerLine = 3) {
let line = '';
eachArray(items, (item, index) => {
line += item;
if ((index + 1) % maxPerLine === 0) {
console.log(line);
line = '';
} else {
line += ', ';
}
});
if (line) console.log(line);
}
模式 8:反向搜索
import { findLastIndex } from '@x-oasis/find-last-index';
const logs = [
{ level: 'info', msg: '已启动' },
{ level: 'info', msg: '处理中' },
{ level: 'error', msg: '失败' },
{ level: 'info', msg: '重试中' },
];
const lastError = findLastIndex(
logs,
log => log.level === 'error'
);
console.log(`最后错误在索引:${lastError}`);
模式 9:组合转换
import { groupBy } from '@x-oasis/group-by';
import { omit } from '@x-oasis/omit';
import { uniqueArrayObject } from '@x-oasis/unique-array-object';
class DataProcessor {
private transformations: Array<(data: any) => any> = [];
filter(predicate: (item: any) => boolean) {
this.transformations.push(data => data.filter(predicate));
return this;
}
map(fn: (item: any) => any) {
this.transformations.push(data => data.map(fn));
return this;
}
groupBy(key: string) {
this.transformations.push(data => groupBy(data, key));
return this;
}
omitFields(keys: string[]) {
this.transformations.push(data =>
Array.isArray(data)
? data.map(item => omit(item, keys))
: omit(data, keys)
);
return this;
}
execute(data: any) {
return this.transformations.reduce((acc, fn) => fn(acc), data);
}
}
const result = new DataProcessor()
.filter(user => user.isActive)
.map(user => ({ ...user, name: user.name.toUpperCase() }))
.omitFields(['password', 'secret'])
.execute(users);
最佳实践
✅ 做法
const result = groupBy(
users.filter(u => u.active).map(u => omit(u, ['temp'])),
'role'
);
const summary = Object.entries(groupBy(sales, 'region')).map(
([region, items]) => ({
region,
total: items.sum(s => s.amount),
})
);
const safe = omit(user, ['passwordHash', 'apiKey', 'internalId']);
❌ 不做法
users.forEach(u => u.id = null);
const updated = users.map(u => omit(u, ['id']));
const all = [];
for (const item of items) {
all.push(item);
}
常见陷阱
陷阱 1:忘记不可变性
const user = { id: 1, name: 'John', secret: 'xxx' };
delete user.secret;
return user;
import { omit } from '@x-oasis/omit';
return omit(user, ['secret']);
陷阱 2:groupBy 缺失键
const items = [
{ type: 'A', value: 1 },
{ value: 2 },
];
groupBy(items, 'type');
const filtered = items.filter(i => i.type);
groupBy(filtered, 'type');
陷阱 3:唯一比较
const items = [
{ id: 1, name: 'A' },
{ id: 1, name: 'A' },
];
uniqueArrayObject(items);
const items = items.map(i => ({ id: i.id, name: i.name }));
参考资料