ArkTS 语言笔记(三):函数、箭头函数和闭包

ArkTS 语言笔记(三):函数、箭头函数和闭包

这一篇主要整理 ArkTS 里的“函数相关内容”:函数声明、可选参数、rest 参数、返回值、作用域、回调、箭头函数、闭包,以及函数重载。
还是以“自己以后翻笔记能看得懂”为目标,不追求教科书式的严肃。

鸿蒙开发者第四期活动


一、函数声明:从一个最普通的例子开始

在 ArkTS 里,函数的标准写法和 TypeScript 非常像:函数名 + 参数列表 + 返回类型 + 函数体

先看官方给的这个例子:

function add(x: string, y: string): string {
  let z: string = `${x} ${y}`;
  return z;
}

这个函数有几点可以注意一下:

  1. 参数类型
    • x: string, y: string
    • 每个参数后面都要显式写上类型。
  2. 返回值类型
    • ): string 表示函数的返回值是 string 类型。
  3. 函数体内部可以继续声明局部变量
    • 比如 let z: string = ...,这个变量只在函数体内部可见。

在 ArkTS 里,函数声明有两个硬性要求:

  • 每个参数都要标类型;
  • 函数的最后一个参数可以是 rest 参数(后面会讲)。

二、可选参数:一个参数“有也行、没也行”

有些参数不是每次调用都需要,这种就可以写成可选参数

2.1 name?: Type 形式

语法形式:

function hello(name?: string) {
  if (name == undefined) {
    console.info('Hello!');
  } else {
    console.info(`Hello, ${name}!`);
  }
}

这里的 name?: string 表示:

  • 这个参数是 string 类型;
  • 调用的时候可以省略:
hello();          // 输出:Hello!
hello('ArkTS');   // 输出:Hello, ArkTS!

2.2 默认参数:给一个“兜底值”

还有一种写法是给参数设置默认值,没传的时候就用默认值:

function multiply(n: number, coeff: number = 2): number {
  return n * coeff;
}

multiply(2);    // 返回 4  → 2 * 2
multiply(2, 3); // 返回 6  → 2 * 3
  • 不传第二个参数时,coeff 自动等于 2
  • 这种写法用起来比在函数体里手动判断要舒服不少。

三、rest 参数:接不定个数的实参

有时候我们希望函数能接收“任意个”参数,比如求和,这时可以使用 rest 参数

语法:...restName: Type[],而且它必须出现在参数列表的最后一个位置

function sum(...numbers: number[]): number {
  let res = 0;
  for (let n of numbers) {
    res += n;
  }
  return res;
}

sum();            // 返回 0
sum(1, 2, 3);     // 返回 6
sum(10, 20, 30);  // 返回 60

在函数内部,numbers 就是一个 number[] 类型的数组,可以正常用 for-oflength 等操作。


四、返回类型:写 or 不写?

4.1 显式写返回类型

当你希望这个函数的“对外约定”非常清晰时,建议像下面这样写:

function foo(): string {
  return 'foo';
}

4.2 让 ArkTS 推断

有些简单函数,编译器能从 return 表达式里推断出返回类型:

function goo() {
  return 'goo';  // 推断返回类型为 string
}

4.3 不返回值:void

不打算返回任何值的函数,可以:

  • 要么省略返回类型;
  • 要么显式写成 void

这两种写法都合法:

function hi1() {
  console.info('hi');
}

function hi2(): void {
  console.info('hi');
}

一般来说:

  • 工程代码里,对外暴露的函数/方法建议写上返回类型
  • 内部的小工具函数可以适当使用类型推断。

五、函数作用域:内部变量不会“漏”出去

函数里定义的变量,只在函数里面有效:

let outerVar = 'I am outer ';

function func() {
  let outerVar = 'I am inside';
  console.info(outerVar); // 输出:I am inside
}

func();
console.info(outerVar);   // 输出:I am outer

这里有两个要点:

  1. 函数内部的 outerVar 是一个新的局部变量,屏蔽了外面的同名变量;
  2. 函数执行完之后,内部的局部变量不会跑到外面来。

作用域这块如果配合闭包一起理解,会更清晰,后面专门聊。


六、函数调用:形参和实参怎么对上号

以这个函数为例:

function join(x: string, y: string): string {
  let z: string = `${x} ${y}`;
  return z;
}

调用方式很直观:

let x = join('hello', 'world');
console.info(x);  // 输出:hello world

需要注意的是:

  • 这里 join 要求两个参数都是 string
  • 少传或类型不对,在 ArkTS 中会直接报编译错误。

七、函数类型:回调函数怎么写得更清楚

ArkTS 中可以用 type 给函数类型起一个名字,常用来定义回调的“形状”。

type trigFunc = (x: number) => number;  // 这是一个函数类型

function do_action(f: trigFunc) {
  f(3.141592653589); // 调用回调函数
}

do_action(Math.sin); // 传入 sin 函数

这样写有两个好处:

  1. 调用方一眼就能看出 do_action 期望的是“接受 number 返回 number 的函数”;
  2. 后续如果有多个地方用到这个回调类型,只要改一处定义就够了。

八、箭头函数:写法更短一点

箭头函数(也叫 Lambda)在 ArkTS 中非常常用。

基本形式:

let sum = (x: number, y: number): number => {
  return x + y;
};

如果函数体只有一个表达式,可以省略 return 和花括号:

let sum1 = (x: number, y: number) => { return x + y; };
let sum2 = (x: number, y: number) => x + y;  // 更简洁

这两种写法在语义上是等价的,主要看风格和可读性。

一般我自己的习惯是:

  • 逻辑比较简单的一两行 → 用“无花括号版”的箭头函数;
  • 逻辑中有多条语句、条件判断等 → 乖乖写成完整函数体。

九、闭包:让函数“记住”当时的环境

闭包的概念简单说就是:

函数 + 创建这个函数时的变量环境。

看下面这个例子:

function f(): () => number {
  let count = 0;
  let g = (): number => { 
    count++; 
    return count; 
  };
  return g;
}

let z = f();
z(); // 返回:1
z(); // 返回:2

这里发生了什么?

  1. 调用 f() 时:
    • f 的内部创建了一个局部变量 count,初始值为 0
    • 定义了一个箭头函数 g,它会访问并修改 count
    • f() 返回这个内部函数 g
  2. z 拿到的就是这个内部函数 g,但重点是:
    • g 把当时的“环境”也一起带了出来(也就是对 count 的引用);
    • 即使 f() 已经执行结束,count 仍然活着,每次调用 z() 都在基于上一次的值继续加 1。

这就是闭包最典型的用法之一:创建一个拥有“私有状态”的函数


十、函数重载:同一个名字,多种用法

ArkTS 支持类似 TypeScript 的函数重载,即:同名函数,多个不同的“调用签名”。

示例:

function foo(x: number): void;            /* 第一个函数定义 */
function foo(x: string): void;            /* 第二个函数定义 */
function foo(x: number | string): void {  /* 函数实现 */
  // 在这里通过类型判断分别处理
}

可以看到:

  • 上面前两行是两个重载签名
  • 最后一行是真实实现,参数类型写成了联合类型 number | string

调用的时候:

foo(123);    // OK,匹配第一个重载
foo('aa');   // OK,匹配第二个重载

需要注意:

  • 不允许有完全相同参数列表的两个重载,那样编译会报错;
  • 实现函数只能有一个,签名可以有多个。

重载的目的就是让一个函数名支持多种使用方式,同时又能给每种方式精准地加上类型约束。


小结:这一篇你可以拿来干嘛?

这篇主要把 ArkTS 的“函数板块”系统过了一遍,包括:

  • 函数声明、可选参数、默认参数、rest 参数;
  • 返回类型、void、作用域;
  • 函数类型(特别是回调函数);
  • 箭头函数的写法;
  • 闭包的核心思想和一个典型例子;
  • 函数重载的写法和注意点。
posted @ 2025-12-03 15:38  遇到困难睡大觉哈哈  阅读(161)  评论(0)    收藏  举报