散修带你入门鸿蒙应用开发基础第八节:高阶函数核心解析与应用
ArkTS基础第八节:高阶函数核心解析与应用
炼气八重天
【学习目标】
- 理解高阶函数的核心定义,明确其与闭包、箭头函数的关联(衔接前两节知识点)。
- 掌握ArkTS中高阶函数的两类核心实现形式(函数作为参数、函数作为返回值),能编写基础自定义高阶函数。
- 熟练运用ArkTS内置高阶函数(
map/filter/reduce)简化数组操作,提升集合处理效率。 - 了解高阶函数的基础应用场景,规避过度封装导致的可读性下降问题。
【学习重点】
- 高阶函数核心定义:满足“函数作为参数传入”或“函数作为返回值导出”其一的函数。
- 实现形式:函数作为参数(基础场景)、函数作为返回值(结合闭包);
- 内置工具:
map(数组映射)、filter(数组过滤)、reduce(数组归并)的基础用法; - 实战场景:集合数据转换、条件筛选、数据聚合;
- 避坑要点:避免无意义的多层高阶函数嵌套,保障代码可读性。
【温馨提示】
高阶函数是闭包与箭头函数的“组合技能”,核心依赖前两节的基础语法,是ArkTS实现代码复用、简化集合操作的核心工具,基础阶段聚焦“会用”而非“深度封装”。
一、高阶函数的核心概念
1.1 高阶函数的定义
在ArkTS中,高阶函数是指满足以下任一条件的函数:
- 函数作为参数:接收一个或多个函数类型的参数;
- 函数作为返回值:执行后返回一个新的函数(通常结合闭包实现)。
核心关联:高阶函数常与闭包结合使用,返回函数的高阶函数本质是闭包的封装形式,二者共同实现“逻辑复用+状态保留”。
1.2 高阶函数与普通函数的对比
- 普通函数:参数和返回值均为基础类型/对象(如
number/string/interface实例); - 高阶函数:参数或返回值为函数类型,支持逻辑的动态注入和复用。
/**
* 普通函数:固定逻辑的加法运算
* 功能:仅能实现两个数字的加法,逻辑不可动态调整
* @param a 第一个加数(number类型)
* @param b 第二个加数(number类型)
* @returns 两个数字的和(number类型)
*/
function add(a: number, b: number): number {
return a + b;
}
/**
* 高阶函数:通用计算工具
* 功能:接收两个数字和自定义计算逻辑,动态执行不同运算
* @param a 待计算的第一个数字(number类型)
* @param b 待计算的第二个数字(number类型)
* @param func 计算逻辑函数(接收两个number类型参数,返回number类型结果)
* @returns 执行自定义计算逻辑后的结果(number类型)
* 核心优势:无需修改函数本体,仅替换func参数即可实现加减乘除等不同运算
*/
function calculate(a: number, b: number, func: (x: number, y: number) => number): number {
// 执行外部传入的自定义计算逻辑,实现逻辑解耦
return func(a, b);
}
/**
* 高阶函数调用示例
* 场景1:传入加法逻辑,计算5+3
* 场景2:传入乘法逻辑,计算5×3
* 场景3:传入减法逻辑,计算5-3
* 说明:通过动态注入不同逻辑,实现同一函数支持多类运算
*/
const sumResult = calculate(5, 3, (x, y) => x + y);
const mulResult = calculate(5, 3, (x, y) => x * y);
const subResult = calculate(5, 3, (x, y) => x - y);
console.log(`加法结果:${sumResult}`); // 输出:8
console.log(`乘法结果:${mulResult}`); // 输出:15
console.log(`减法结果:${subResult}`); // 输出:2
二、高阶函数的两大核心实现形式
2.1 形式一:函数作为参数(基础高频场景)
这是高阶函数最基础的实现形式,核心是“将逻辑作为参数传入”,实现动态的逻辑复用。
2.1.1 实战示例:通用数据处理器
/**
* 高阶函数:通用数据处理器
* 功能:接收任意数字和自定义处理逻辑,返回处理后的结果
* @param data 待处理的原始数字(number类型)
* @param handler 处理逻辑函数(接收number类型参数,返回number类型结果)
* @returns 执行处理逻辑后的数字结果(number类型)
* 应用场景:统一数据处理入口,支持翻倍、加值、取模、平方等多种操作
*/
function processData(data: number, handler: (num: number) => number): number {
// 执行外部传入的处理逻辑,实现逻辑解耦和动态替换
return handler(data);
}
/**
* 通用数据处理器调用示例
* 场景1:将数字10翻倍(注入翻倍逻辑)
* 场景2:将数字10加5(注入加值逻辑)
* 场景3:将数字10取模3(注入取模逻辑)
* 场景4:将数字10平方(注入平方逻辑)
*/
const doubleResult = processData(10, (num) => num * 2);
const add5Result = processData(10, (num) => num + 5);
const mod3Result = processData(10, (num) => num % 3);
const squareResult = processData(10, (num) => num * num);
console.log(`翻倍结果:${doubleResult}`); // 输出:20
console.log(`加5结果:${add5Result}`); // 输出:15
console.log(`取模3结果:${mod3Result}`); // 输出:1
console.log(`平方结果:${squareResult}`); // 输出:100
2.2 形式二:函数作为返回值(结合闭包)
该形式本质是闭包的封装,外层高阶函数接收配置参数,返回的内层函数实现具体逻辑,兼顾“配置复用”和“状态保留”。
2.2.1 实战示例:带固定步长的累加器
/**
* 高阶函数:创建带固定步长的累加器
* 功能:接收累加步长,返回可复用的累加函数
* @param step 累加步长(如3表示每次调用加3,number类型)
* @returns 累加逻辑函数(接收number类型参数,返回number+step的结果)
* 核心原理:内层箭头函数形成闭包,永久保留外层step参数的引用
* 优势:一次配置步长,多次复用累加逻辑,无需重复传递step参数
*/
function createAdder(step: number): (num: number) => number {
// 闭包特性:内层函数可访问外层函数的step参数,且step不会被垃圾回收
return (num: number) => num + step;
}
/**
* 累加器使用示例
* 1. 创建步长为3的累加器,复用计算10+3、20+3
* 2. 创建步长为10的累加器,复用计算5+10、15+10
* 说明:不同累加器的step参数相互独立,闭包保证各自的状态隔离
*/
const add3 = createAdder(3);
console.log(`10+3 = ${add3(10)}`); // 输出:13
console.log(`20+3 = ${add3(20)}`); // 输出:23
const add10 = createAdder(10);
console.log(`5+10 = ${add10(5)}`); // 输出:15
console.log(`15+10 = ${add10(15)}`); // 输出:25
三、ArkTS内置高阶函数(数组操作核心工具)
ArkTS为数组提供了map/filter/reduce等内置高阶函数,可快速实现数据映射、筛选、聚合,避免手动编写循环逻辑,提升代码简洁性。
3.1 map:数组映射(一对一转换)
核心功能:遍历数组,对每个元素执行指定转换逻辑,返回长度与原数组一致的新数组(原数组不修改)。
/**
* map实战:成绩等级转换
* 功能:将数字分数数组转换为对应的等级数组(A/B/C/D)
* 核心逻辑:一对一映射,每个分数对应一个等级,新数组长度与原数组一致
*/
// 原始分数数组
const scores: number[] = [85, 92, 78, 66];
/**
* map回调函数说明:
* @param score 当前遍历的分数元素(number类型)
* @returns 转换后的等级字符串(string类型)
* 等级规则:≥90→A,≥80→B,≥70→C,其他→D
*/
const levels = scores.map((score) => {
if (score >= 90) return "A";
if (score >= 80) return "B";
if (score >= 70) return "C";
return "D";
});
console.log(`原始分数数组:${scores}`); // 输出:85,92,78,66(原数组不变)
console.log(`转换后等级数组:${levels}`); // 输出:B,A,C,D(新数组)
3.2 filter:数组过滤(按条件筛选)
核心功能:遍历数组,仅保留回调函数返回true的元素,返回长度≤原数组的新数组(原数组不修改)。
/**
* filter实战:筛选及格成绩
* 功能:从所有分数中筛选出≥60的及格分数
* 核心逻辑:回调函数返回true则保留元素,false则剔除
*/
// 所有学生的分数数组
const allScores: number[] = [55, 88, 95, 58, 72];
/**
* filter回调函数说明:
* @param score 当前遍历的分数元素(number类型)
* @returns 布尔值(true=保留,false=剔除)
* 筛选规则:分数≥60为及格,保留;否则剔除
*/
const passScores = allScores.filter((score) => score >= 60);
console.log(`原始分数数组:${allScores}`); // 输出:55,88,95,58,72(原数组不变)
console.log(`及格分数数组:${passScores}`); // 输出:88,95,72(筛选后的新数组)
3.3 reduce:数组归并(聚合计算)
核心功能:遍历数组,将所有元素按回调逻辑聚合为单个值(如求和、求积、统计总数),是数组聚合的核心工具。
/**
* reduce实战1:数组求和
* 功能:计算数字数组中所有元素的总和
* 核心逻辑:累加器(sum)保存上一轮结果,与当前元素(current)累加
* @param sum 累加器(上一轮的求和结果,number类型)
* @param current 当前遍历的元素(number类型)
* @param 0 累加器初始值(必填,避免数组为空时出错)
*/
const nums: number[] = [1, 2, 3, 4, 5];
const total = nums.reduce((sum, current) => sum + current, 0);
console.log(`数组总和:${total}`); // 输出:15(1+2+3+4+5)
/**
* reduce实战2:计算成绩平均分
* 功能:先求和所有分数,再除以人数得到平均分
* 步骤拆解:1. reduce求和 → 2. 总和 ÷ 数组长度 = 平均分
*/
const studentScores: number[] = [80, 90, 75, 85];
const averageScore = studentScores.reduce((sum, score) => sum + score, 0) / studentScores.length;
console.log(`成绩平均分:${averageScore}`); // 输出:82.5
3.4 内置高阶函数链式调用(基础进阶)
可将map/filter/reduce链式组合,实现复杂数据处理逻辑,简化多层循环嵌套。
/**
* 链式调用实战:筛选及格成绩并转换为等级
* 功能:先筛选出及格分数,再将及格分数转换为对应的等级
* 优势:无需定义中间变量,代码简洁且逻辑连贯
* 步骤拆解:1. filter筛选及格分数 → 2. map转换为等级
*/
const allStudentScores: number[] = [55, 88, 95, 58, 72, 83];
const passLevels = allStudentScores
.filter((score) => score >= 60) // 第一步:筛选及格分数
.map((score) => { // 第二步:转换为等级
if (score >= 90) return "A";
if (score >= 80) return "B";
return "C";
});
console.log(`及格成绩等级:${passLevels}`); // 输出:B,A,C,B
四、高阶函数的基础应用场景
4.1 场景1:集合数据格式转换
/**
* 场景1:价格格式转换
* 功能:将数字价格数组转换为带人民币单位的字符串数组(保留2位小数)
* 应用场景:前端展示价格时的格式统一处理
*/
const prices: number[] = [19.9, 29.9, 39.9];
/**
* map回调逻辑:
* @param price 当前遍历的价格数字(number类型)
* @returns 格式化后的价格字符串(如¥19.90)
* 格式化规则:拼接¥符号 + 保留2位小数
*/
const priceStrs = prices.map((price) => `¥${price.toFixed(2)}`);
console.log(`格式化后价格数组:${priceStrs}`); // 输出:¥19.90,¥29.90,¥39.90
4.2 场景2:条件筛选+数据聚合
/**
* 场景2:筛选偶数并求和
* 功能:先筛选数组中的偶数,再计算偶数的总和
* 步骤拆解:1. filter筛选偶数 → 2. reduce求和
* 应用场景:数据统计类业务(如统计偶数金额、偶数数量等)
*/
const numList: number[] = [1, 2, 3, 4, 5, 6, 7, 8];
const evenTotal = numList
.filter((num) => num % 2 === 0) // 筛选偶数
.reduce((sum, num) => sum + num, 0); // 对偶数求和
console.log(`偶数总和:${evenTotal}`); // 输出:20(2+4+6+8)
4.3 场景3:带配置的逻辑复用(结合闭包)
/**
* 高阶函数:创建按阈值筛选的通用筛选器
* 功能:接收筛选阈值,返回可复用的筛选函数
* @param threshold 筛选阈值(number类型,如5表示筛选大于5的数字)
* @returns 筛选逻辑函数(接收number,返回boolean)
* 核心原理:闭包保留threshold参数,实现筛选逻辑的定制化复用
*/
function createThresholdFilter(threshold: number): (num: number) => boolean {
return (num) => num > threshold;
}
/**
* 通用筛选器使用示例
* 场景1:创建阈值为5的筛选器,筛选大于5的数字
* 场景2:创建阈值为7的筛选器,筛选大于7的数字
* 说明:通过闭包保留不同阈值,实现筛选逻辑的复用
*/
const filterGreaterThan5 = createThresholdFilter(5);
const result1 = [3, 6, 8, 2, 9].filter(filterGreaterThan5);
console.log(`大于5的数字:${result1}`); // 输出:6,8,9
const filterGreaterThan7 = createThresholdFilter(7);
const result2 = [3, 6, 8, 2, 9].filter(filterGreaterThan7);
console.log(`大于7的数字:${result2}`); // 输出:8,9
五、高阶函数避坑要点(基础版)
5.1 避免无意义的多层嵌套
/**
* 避坑示例:避免多层高阶函数嵌套
* 反面案例:嵌套层数过多,逻辑晦涩,可读性差
* 正面案例:拆分逻辑为独立函数,结构清晰,易维护
*/
// 不推荐:多层嵌套,逻辑难以理解
const complexResult = [1,2,3].map((num: number): number => {
return (() => num * 2)();
}).filter((num): boolean => {
return (() => num > 3)();
});
// 推荐:拆分逻辑为独立函数,提升可读性
/**
* 独立函数:数字翻倍逻辑
* @param num 待翻倍的数字(number类型)
* @returns 翻倍后的数字(number类型)
*/
const doubleNum = (num: number) => num * 2;
/**
* 独立函数:判断数字是否大于3
* @param num 待判断的数字(number类型)
* @returns 布尔值(true=大于3,false=不大于3)
*/
const isGreaterThan3 = (num: number) => num > 3;
const simpleResult = [1,2,3].map(doubleNum).filter(isGreaterThan3);
console.log(`简化后结果:${simpleResult}`); // 输出:4,6
5.2 明确函数类型标注
/**
* 避坑示例:明确函数类型标注
* 错误案例:无类型标注,易引发隐式any类型错误(ArkTS强类型语言不推荐)
* 正确案例:显式标注所有参数和返回值类型,提升代码健壮性
*/
// 错误示例(注释掉,避免编译报错)
// function badFunc(data, handler) {
// return handler(data);
// }
// 正确示例:显式类型标注
/**
* 规范的高阶函数写法
* @param data 待处理数字(number类型)
* @param handler 处理函数(接收number类型参数,返回string类型结果)
* @returns 处理后的字符串结果(string类型)
*/
function goodFunc(data: number, handler: (num: number) => string): string {
return handler(data);
}
5.3 避免过度封装
简单逻辑无需封装为高阶函数,例如单一的加法计算直接用普通函数实现即可,避免过度设计导致代码冗余。
六、课堂小结
- 核心定义:高阶函数是接收函数作为参数或返回函数的特殊函数,常与闭包结合实现逻辑复用。
- 实现形式:函数作为参数(基础场景)、函数作为返回值(结合闭包),二者可灵活组合。
- 内置工具:
map实现数组映射、filter实现条件筛选、reduce实现数据聚合,支持链式调用。 - 应用场景:集合数据转换、条件筛选、带配置的逻辑复用,是简化数组操作的核心工具。
- 避坑要点:控制嵌套层数、明确类型标注、避免过度封装,保障代码可读性。
七、课后练习
- 基础实现题:使用
map将数组[1,2,3,4]转换为["1号","2号","3号","4号"]格式。 - 组合实战题:先通过
filter筛选出数组[10,15,20,25,30]中能被5整除且大于15的数,再用reduce计算它们的乘积。 - 高阶封装题:实现高阶函数
createMultiplier(factor: number),返回一个函数,该函数接收数字并返回其与factor的乘积(结合闭包)。
八、课后练习参考答案与解析
8.1 数组格式转换
/**
* 练习1参考答案:数组格式转换
* 功能:将数字数组[1,2,3,4]转换为["1号","2号","3号","4号"]
* 核心逻辑:利用map的一对一映射特性,对每个元素做字符串拼接
*/
const nums: number[] = [1,2,3,4];
const numStrs = nums.map((num) => `${num}号`);
console.log(`转换结果:${numStrs}`); // 输出:1号,2号,3号,4号
- 解析:利用
map的一对一映射特性,直接对每个元素做字符串拼接,保留原数组长度。
8.2 筛选+聚合实战
/**
* 练习2参考答案:筛选+聚合
* 功能:筛选能被5整除且>15的数字,计算它们的乘积
* 步骤拆解:1. filter筛选符合条件的数字 → 2. reduce累乘(初始值为1)
*/
const arr: number[] = [10,15,20,25,30];
const product = arr
.filter((num) => num % 5 === 0 && num > 15) // 筛选条件:能被5整除且>15
.reduce((prod, num) => prod * num, 1); // 累乘(初始值为1,避免乘积为0)
console.log(`筛选后乘积:${product}`); // 输出:20*25*30=15000
- 解析:
filter先筛选出符合条件的元素[20,25,30],reduce从1开始累乘,最终得到乘积结果。
8.3 高阶函数封装
/**
* 练习3参考答案:通用乘法器(高阶函数+闭包)
* 功能:创建可复用的乘法器,支持自定义乘数
* @param factor 乘数(number类型,如3表示乘以3)
* @returns 乘法逻辑函数(接收number类型参数,返回num*factor的结果)
* 核心原理:闭包保留factor参数,实现乘法逻辑的定制化复用
*/
function createMultiplier(factor: number): (num: number) => number {
return (num) => num * factor;
}
/**
* 乘法器使用示例
* 创建乘数为3的乘法器,计算5×3的结果
*/
const multiplyBy3 = createMultiplier(3);
console.log(`5×3的结果:${multiplyBy3(5)}`); // 输出:15
- 解析:外层函数接收乘数
factor,内层箭头函数通过闭包保留该值,调用时只需传入待乘数字,即可复用乘法逻辑。
九、代码仓库
工程名称:HigherOrderFuncDemo本节代码已同步至:https://gitee.com/juhetianxia321/harmony-os-code-base.git
十、下节预告
下一节将进入第九节:模块的导入导出阶段(炼气九重天:高阶函数的工程化复用基础),重点学习:
- 理解ArkTS“文件即模块”的核心规范,明确模块导入导出与高阶函数复用的关联;
- 掌握
export的两类核心方式(命名导出/默认导出),将本节的高阶函数拆分为独立工具模块; - 掌握
import的四类用法(命名导入/默认导入/批量导入/混合导入),灵活调用模块化的高阶函数; - 吃透鸿蒙项目的模块路径规则,解决跨文件调用高阶函数的路径报错问题;
- 落地通用场景的高阶函数模块化实战,为后续接口、类的复用建立工程化基础。
十一、鸿蒙开发者学习与认证指引
(一)、官方学习班级报名(免费)
- 班级链接:HarmonyOS赋能资源丰富度建设(第四期)
- 学号填写规则:填写个人手机号码即可完成班级信息登记
(二)、HarmonyOS应用开发者认证考试(免费)
-
考试链接:HarmonyOS开发者能力认证入口
-
认证等级及适配人群
- 基础认证:适配软件工程师、移动应用开发人员,需掌握HarmonyOS基础概念、DevEco Studio基础使用、ArkTS及ArkUI基础开发等能力;
- 高级认证:适配项目经理、工程架构师,需掌握系统核心技术理念、应用架构设计、关键技术开发及应用上架运维等能力;
- 专家认证:适配研发经理、解决方案专家,需掌握分布式技术原理、端云一体化开发、跨端迁移及性能优化等高级能力。
-
认证权益:通过认证可获得电子版证书以及其他专属权益。
浙公网安备 33010602011771号