鸿蒙学习实战之路:数组高阶方法:map、filter、reduce实战指南
数组高阶方法:map、filter、reduce实战指南
文章简介
在HarmonyOS应用开发中,数组操作是日常开发的重要组成部分。本文将深入探讨三个核心的数组高阶方法:map、filter和reduce,帮助开发者掌握这些强大的数据处理工具。
官方参考资料:
版本说明:本文所有示例基于HarmonyOS Next API 10+ 和 DevEco Studio 4.0+
前置知识
在开始学习高阶方法之前,确保你已了解以下基础概念:
- 数组的基本操作
- 箭头函数语法
- 类型注解基础
- 基本的TS/JS语法
1. map方法详解
1.1 基础概念
map方法用于遍历数组并对每个元素执行指定操作,返回一个新数组。
核心特性:
- 不改变原数组
- 返回新数组长度与原数组相同
- 适合数据转换场景
1.2 基本语法
// 基础语法
const newArray = originalArray.map((currentValue, index, array) => {
// 返回处理后的元素
});
1.3 实战示例
示例1:数值数组转换
// 将价格数组转换为含税价格(税率10%)
const prices: number[] = [100, 200, 300, 400];
const pricesWithTax = prices.map(price => price * 1.1);
console.log(pricesWithTax); // [110, 220, 330, 440]
示例2:对象数组属性提取
interface User {
id: number;
name: string;
age: number;
}
const users: User[] = [
{ id: 1, name: "张三", age: 25 },
{ id: 2, name: "李四", age: 30 },
{ id: 3, name: "王五", age: 28 }
];
// 提取用户姓名数组
const userNames = users.map(user => user.name);
console.log(userNames); // ["张三", "李四", "王五"]
// 添加新属性
const usersWithStatus = users.map(user => ({
...user,
isActive: user.age > 25
}));
1.4 map方法参数详解
| 参数 | 类型 | 描述 | 是否必选 |
|---|---|---|---|
| callback | function | 对每个元素执行的函数 | 是 |
| currentValue | any | 当前处理的元素 | - |
| index | number | 当前元素的索引 | - |
| array | Array | 调用map的数组本身 | - |
| thisArg | any | 执行callback时的this值 | 否 |
2. filter方法详解
2.1 基础概念
filter方法用于筛选数组中满足条件的元素,返回新数组。
核心特性:
- 返回数组长度 ≤ 原数组长度
- 不会改变原数组
- 适合数据筛选场景
2.2 基本语法
const filteredArray = originalArray.filter((currentValue, index, array) => {
// 返回true保留元素,false过滤元素
});
2.3 实战示例
示例1:基础数据筛选
// 筛选偶数
const numbers: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // [2, 4, 6, 8, 10]
示例2:复杂对象筛选
interface Product {
id: number;
name: string;
price: number;
category: string;
inStock: boolean;
}
const products: Product[] = [
{ id: 1, name: "手机", price: 2999, category: "electronics", inStock: true },
{ id: 2, name: "书籍", price: 59, category: "education", inStock: false },
{ id: 3, name: "耳机", price: 399, category: "electronics", inStock: true },
{ id: 4, name: "笔记本", price: 15, category: "office", inStock: true }
];
// 筛选有库存的电子产品
const availableElectronics = products.filter(product =>
product.category === "electronics" && product.inStock
);
console.log(availableElectronics);
// [{ id: 1, name: "手机", ... }, { id: 3, name: "耳机", ... }]
2.4 多条件筛选技巧
// 价格范围筛选
const priceRangeFilter = (minPrice: number, maxPrice: number) => {
return products.filter(product =>
product.price >= minPrice && product.price <= maxPrice
);
};
const affordableProducts = priceRangeFilter(50, 500);
console.log(affordableProducts); // 价格在50-500之间的产品
3. reduce方法详解
3.1 基础概念
reduce方法将数组元素通过 reducer 函数累积为单个值。
核心特性:
- 返回任意类型的单个值
- 功能最强大的数组方法
- 适合聚合计算场景
3.2 基本语法
const result = array.reduce((accumulator, currentValue, index, array) => {
// 返回累积值
}, initialValue);
3.3 实战示例
示例1:数值计算
// 计算数组总和
const numbers: number[] = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, curr) => acc + curr, 0);
console.log(sum); // 15
// 找出最大值
const max = numbers.reduce((acc, curr) => Math.max(acc, curr), numbers[0]);
console.log(max); // 5
示例2:复杂数据聚合
interface OrderItem {
product: string;
quantity: number;
price: number;
}
const orderItems: OrderItem[] = [
{ product: "手机", quantity: 1, price: 2999 },
{ product: "耳机", quantity: 2, price: 399 },
{ product: "保护壳", quantity: 1, price: 59 }
];
// 计算订单总金额
const totalAmount = orderItems.reduce((total, item) => {
return total + (item.quantity * item.price);
}, 0);
console.log(totalAmount); // 3856
// 按产品分类统计
const productStats = orderItems.reduce((stats, item) => {
if (!stats[item.product]) {
stats[item.product] = { totalQuantity: 0, totalRevenue: 0 };
}
stats[item.product].totalQuantity += item.quantity;
stats[item.product].totalRevenue += item.quantity * item.price;
return stats;
}, {} as Record<string, { totalQuantity: number; totalRevenue: number }>);
4. 方法链式组合实战
4.1 数据处理管道
在实际开发中,我们经常需要组合使用这些方法:
interface Employee {
id: number;
name: string;
department: string;
salary: number;
yearsOfExperience: number;
}
const employees: Employee[] = [
{ id: 1, name: "张三", department: "技术部", salary: 15000, yearsOfExperience: 3 },
{ id: 2, name: "李四", department: "技术部", salary: 18000, yearsOfExperience: 5 },
{ id: 3, name: "王五", department: "市场部", salary: 12000, yearsOfExperience: 2 },
{ id: 4, name: "赵六", department: "技术部", salary: 22000, yearsOfExperience: 8 },
{ id: 5, name: "钱七", department: "人事部", salary: 10000, yearsOfExperience: 1 }
];
// 复杂数据处理:技术部员工,经验3年以上,提取姓名和调整后薪资(+10%)
const processedData = employees
.filter(emp => emp.department === "技术部" && emp.yearsOfExperience >= 3)
.map(emp => ({
name: emp.name,
adjustedSalary: Math.round(emp.salary * 1.1), // 薪资调整10%
experience: emp.yearsOfExperience
}))
.reduce((result, emp) => {
result.totalAdjustedSalary += emp.adjustedSalary;
result.employees.push(emp);
return result;
}, { totalAdjustedSalary: 0, employees: [] as Array<{name: string; adjustedSalary: number; experience: number}> });
console.log(processedData);
4.2 性能优化技巧
// 避免在循环中重复计算
const optimizedProcess = (data: Employee[]) => {
// 先过滤,减少后续处理的数据量
return data
.filter(emp => emp.department === "技术部")
.map(emp => {
// 复杂计算只执行一次
const bonus = calculateBonus(emp.yearsOfExperience);
const adjustedSalary = emp.salary + bonus;
return {
...emp,
adjustedSalary,
bonus
};
});
};
// 模拟奖金计算函数
const calculateBonus = (experience: number): number => {
return experience * 500; // 每年经验500元奖金
};
5. HarmonyOS特定应用场景
5.1 UI数据绑定
在HarmonyOS的ArkUI开发中,数组方法常用于数据处理:
// 在HarmonyOS组件中使用
@Component
struct ProductList {
@State products: Product[] = [
{ id: 1, name: "HarmonyOS手机", price: 3999, category: "electronics", inStock: true },
{ id: 2, name: "智能手表", price: 1299, category: "electronics", inStock: true },
{ id: 3, name: "平板电脑", price: 2599, category: "electronics", inStock: false }
];
build() {
Column() {
// 使用filter和map准备显示数据
ForEach(this.products
.filter(product => product.inStock)
.map(product => ({ ...product, displayPrice: `¥${product.price}` })),
(item: Product & { displayPrice: string }) => {
Text(item.name)
.fontSize(16)
Text(item.displayPrice)
.fontSize(14)
.fontColor(Color.Gray)
}
)
}
}
}
5.2 状态管理数据处理
// 在AppStorage或状态管理中处理数组数据
class ShoppingCartService {
private items: CartItem[] = [];
// 添加商品到购物车
addItem(newItem: CartItem) {
this.items = [...this.items, newItem];
}
// 计算总价
getTotalPrice(): number {
return this.items.reduce((total, item) => total + item.price * item.quantity, 0);
}
// 获取商品种类数量
getUniqueProductCount(): number {
return this.items
.map(item => item.productId)
.filter((productId, index, array) => array.indexOf(productId) === index)
.length;
}
// 按分类分组
getItemsByCategory() {
return this.items.reduce((groups, item) => {
const category = item.category;
if (!groups[category]) {
groups[category] = [];
}
groups[category].push(item);
return groups;
}, {} as Record<string, CartItem[]>);
}
}
6. 性能考虑和最佳实践
6.1 性能优化建议
避免的陷阱:
- 不要在render或build方法中进行复杂计算
- 避免创建不必要的中间数组
- 合理使用缓存机制
// 不好的做法:每次渲染都重新计算
@Component
struct BadExample {
@State data: number[] = [1, 2, 3, 4, 5];
build() {
Column() {
// 每次build都会重新计算
ForEach(this.data.map(x => x * 2), (item: number) => {
Text(item.toString())
})
}
}
}
// 好的做法:使用计算属性或缓存
@Component
struct GoodExample {
@State data: number[] = [1, 2, 3, 4, 5];
private cachedData: number[] = [];
// 使用aboutToAppear进行预处理
aboutToAppear() {
this.cachedData = this.data.map(x => x * 2);
}
build() {
Column() {
ForEach(this.cachedData, (item: number) => {
Text(item.toString())
})
}
}
}
6.2 错误处理
// 安全的数组操作
const safeArrayOperations = <T>(array: T[] | null | undefined) => {
// 处理可能的空值或未定义
const safeArray = array || [];
return {
mapped: safeArray.map(item => item),
filtered: safeArray.filter(item => !!item),
reduced: safeArray.reduce((acc, curr) => acc, 0)
};
};
// 在HarmonyOS组件中的错误边界处理
@Component
struct SafeArrayComponent {
@State data: number[] | null = null;
build() {
Column() {
// 使用可选链和空值合并
ForEach((this.data ?? []).map(item => item * 2), (item: number) => {
Text(item.toString())
})
}
}
}
7. 注意事项和重要提示
7.1 常见陷阱
map方法注意事项:
- 一定要有return语句,否则会得到undefined数组
- 不要在有副作用的操作中使用map
- 确保回调函数是纯函数
// 错误示例
const wrongMap = numbers.map(num => {
console.log(num); // 副作用!
// 缺少return语句
});
// 正确做法
const correctMap = numbers.map(num => num * 2);
filter方法注意事项:
- 回调函数必须返回boolean值
- 注意处理空数组情况
- 考虑使用类型守卫
// 使用类型守卫
const mixedArray: (number | string | null)[] = [1, "hello", null, 2, "world"];
// 只保留数字类型
const numbersOnly = mixedArray.filter((item): item is number =>
typeof item === "number"
);
reduce方法注意事项:
- 不要忘记提供初始值
- 确保累积器和当前值类型一致
- 在复杂对象reduce时注意引用问题
// 提供正确的初始值类型
interface Accumulator {
sum: number;
count: number;
}
const stats = numbers.reduce<Accumulator>((acc, curr) => {
return {
sum: acc.sum + curr,
count: acc.count + 1
};
}, { sum: 0, count: 0 }); // 明确的初始值
7.2 性能监控
在大型数组操作时,建议添加性能监控:
const measurePerformance = <T>(operation: string, fn: () => T): T => {
const start = Date.now();
const result = fn();
const end = Date.now();
console.log(`${operation} 耗时: ${end - start}ms`);
return result;
};
// 使用示例
const largeArray = Array.from({ length: 10000 }, (_, i) => i);
const result = measurePerformance('map操作', () =>
largeArray.map(x => x * 2)
);
总结
通过本文的学习,你应该已经掌握了:
- map:用于数据转换,1:1映射
- filter:用于数据筛选,返回子集
- reduce:用于数据聚合,返回单个值
- 方法链:组合使用实现复杂数据处理
这些高阶方法在HarmonyOS应用开发中极其重要,特别是在:
- UI数据准备
- 状态管理
- 业务逻辑处理
- 数据格式化
实践建议:
- 在简单循环场景优先考虑高阶方法
- 注意性能,避免不必要的中间数组
- 合理使用方法
需要参加鸿蒙认证的请点击 鸿蒙认证链接

浙公网安备 33010602011771号