ArkTS 语言笔记(三):函数、箭头函数和闭包
ArkTS 语言笔记(三):函数、箭头函数和闭包
这一篇主要整理 ArkTS 里的“函数相关内容”:函数声明、可选参数、rest 参数、返回值、作用域、回调、箭头函数、闭包,以及函数重载。
还是以“自己以后翻笔记能看得懂”为目标,不追求教科书式的严肃。
一、函数声明:从一个最普通的例子开始
在 ArkTS 里,函数的标准写法和 TypeScript 非常像:函数名 + 参数列表 + 返回类型 + 函数体。
先看官方给的这个例子:
function add(x: string, y: string): string {
let z: string = `${x} ${y}`;
return z;
}
这个函数有几点可以注意一下:
- 参数类型
x: string, y: string- 每个参数后面都要显式写上类型。
- 返回值类型
): string表示函数的返回值是string类型。
- 函数体内部可以继续声明局部变量
- 比如
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-of、length 等操作。
四、返回类型:写 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
这里有两个要点:
- 函数内部的
outerVar是一个新的局部变量,屏蔽了外面的同名变量; - 函数执行完之后,内部的局部变量不会跑到外面来。
作用域这块如果配合闭包一起理解,会更清晰,后面专门聊。
六、函数调用:形参和实参怎么对上号
以这个函数为例:
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 函数
这样写有两个好处:
- 调用方一眼就能看出
do_action期望的是“接受number返回number的函数”; - 后续如果有多个地方用到这个回调类型,只要改一处定义就够了。
八、箭头函数:写法更短一点
箭头函数(也叫 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
这里发生了什么?
- 调用
f()时:- 在
f的内部创建了一个局部变量count,初始值为0; - 定义了一个箭头函数
g,它会访问并修改count; f()返回这个内部函数g。
- 在
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、作用域; - 函数类型(特别是回调函数);
- 箭头函数的写法;
- 闭包的核心思想和一个典型例子;
- 函数重载的写法和注意点。

浙公网安备 33010602011771号