ArkTS基础语法 |(2)函数

ArkTS基础语法 |(2)函数

在学习HarmonyOS开发的核心语言ArkTS时,整理了一份基础语法笔记,方便日后回顾。

函数能够封装重复的业务逻辑(代码块),遵循先定义、后调用 的基本原则,大幅提升代码的复用率和可维护性。

一、函数声明

ArkTS中声明函数需明确函数名、参数列表、返回类型(可选)和函数体

  • 声明函数的核心规则:
  1. 形参必须显式标记类型,实参的数量、类型需与形参一一对应。

  2. 仅定义函数不调用,函数体代码不会执行。

  3. 支持无参无返回值、带参带返回值等多种形式。

  4. 可通过return关键字返回处理结果,无返回值时可省略return

1. 无参无返回值函数

最基础的函数形式,无参数传入,也无结果返回,适用于执行简单的固定逻辑。

TypeScript 复制代码
// 定义语法
function 函数名() {
  函数体
}
// 调用语法
函数名()

// 示例
function sayHello() {
  console.log('Hello ArkTS!');   // 执行简单的打印逻辑
}
sayHello();   // 调用后输出:Hello ArkTS!
2. 带参带返回值函数

适用于需要传入参数并返回处理结果的场景,需指定形参类型函数返回类型

  • 形参:函数定义时的参数,必须指定类型。

  • 实参:函数调用时传入的参数,需与形参数量、类型严格匹配。

  • return :用于返回处理结果,执行到return后函数体立即终止。

TypeScript 复制代码
// 示例:定义求和函数,接收两个number类型参数,返回number类型结果。
function sum(num1: number, num2: number): number {
  return num1 + num2;   // 返回两数之和
}
// 调用函数,接收返回值并打印。
let result: number = sum(10, 20);
console.log(result);   // 输出:30

二、函数参数

ArkTS对函数参数做了灵活扩展,支持必选参数、可选参数、默认值参数、rest参数 ,其中可选参数、默认值参数、rest参数均需遵循特定的语法规则,且只能出现在必选参数之后

1. 可选参数

调用函数时可省略的参数 语法:参数名?: 类型 省略时参数值为undefined,需在函数体内做判空处理。

  • 注意:可选参数必须跟在必选参数后面,不能放在必选参数之前。
TypeScript 复制代码
// 示例
function hello(name?: string) {
  if (name == undefined) {
    console.info('Hello!');   // 省略参数时执行
  } else {
    console.info(`Hello, ${name}!`);   // 传入参数时执行
  }
}
hello();   // 省略参数 输出:Hello!
hello('ArkTS');   // 传入参数 输出:Hello, ArkTS!
2. 默认值参数

可选参数的另一种形式,为参数设置默认值,调用时若省略该参数,会自动使用默认值作为实参. 语法:参数名: 类型 = 默认值

  • 注意:默认值参数也需跟在必选参数之后,若调用时传入新值,会覆盖默认值。
TypeScript 复制代码
// 示例:定义乘法函数,系数coeff设置默认值2。
function multiply(n: number, coeff: number = 2): number {
  return n * coeff;
}
multiply(2);   // 省略coeff,使用默认值2,返回:4。
multiply(2, 3);   // 传入coeff=3,覆盖默认值,返回:6。
3. rest参数

用于处理不定数量的参数输入 ,允许函数接收一个不定长的数组。 语法...rest参数名: 类型[] 核心规则:

  1. rest参数只能是函数的最后一个参数
  2. rest参数的类型必须是数组类型
  3. 调用时可传入0个、1个或多个同类型参数,均会被封装为数组。
TypeScript 复制代码
// 示例:定义求和函数,支持传入任意多个number类型参数.
function sum(...numbers: number[]): number {
  let res = 0;
  // 遍历rest参数数组,累加求和
  for (let n of numbers) {
    res += n;
  }
  return res;
}
sum();   // 传入0个参数 返回:0
sum(1, 2, 3);   // 传入3个参数 返回:6
sum(10, 20, 30, 40);   // 传入4个参数 返回:100

三、函数返回类型

ArkTS中函数的返回类型支持显式指定自动推断 ,无返回值时可指定为void类型. 核心规则:

  1. 若函数体的返回结果可被编译器推断,可省略返回类型标注。
  2. 无返回值的函数,可显式指定void或省略返回类型。
  3. 显式指定返回类型后,函数返回的结果必须与该类型匹配,否则编译报错。
1. 显式指定返回类型

适用于需要明确函数返回值类型的场景,提升代码的可读性和规范性。

TypeScript 复制代码
// 显式指定返回string类型
function foo(): string { 
  return 'foo'; 
}
// 显式指定返回number类型
function getNum(): number {
  return 100;
}
2. 自动推断返回类型

编译器可根据函数体的return语句自动推断返回类型,可省略返回类型标注,简化代码。

TypeScript 复制代码
// 自动推断返回类型为string
function goo() { 
  return 'goo'; 
}
// 自动推断返回类型为boolean
function isTrue() {
  return 1 > 0;
}
3. 无返回值(void类型)

表示函数无任何返回结果,即使写return也不能携带值,两种声明方式均可,效果一致。

TypeScript 复制代码
// 方式1:省略返回类型标注(简洁写法)
function hi1() { 
  console.info('hi'); 
}

// 方式2:显式指定void类型(规范写法)
function hi2(): void { 
  console.info('hi'); 
  // 无返回值的函数可写空return,不可写return 123(编译报错)。
  return;
}
4. 拓展:never类型

表示函数永远不会执行完成 (如函数内抛出异常、无限循环),是比void更严格的返回类型,基础开发中使用较少,做简单了解即可。

TypeScript 复制代码
function errorFunc(): never {
  throw new Error('程序执行异常');
}

四、函数的作用域

ArkTS中函数遵循块级作用域 规则,函数内定义的变量/实例为局部变量 ,函数外定义的为全局变量。 核心规则:

  1. 局部变量仅能在函数内部访问,外部无法访问。
  2. 若函数内的局部变量与全局变量同名,局部变量会覆盖全局变量(函数内优先使用局部变量)。
  3. 函数内定义变量时,必须使用let/const,否则会被提升为全局变量。
TypeScript 复制代码
// 定义全局变量
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(全局变量未被修改)

// 易错点:函数内未用let/const定义的变量,会成为全局变量。
function badFunc() {
  testVar = '全局变量';   // 未用let/const,提升为全局变量
}
badFunc();
console.info(testVar);   // 输出:全局变量

五、函数的调用

函数定义后,需通过 函数名(实参) 的方式调用,才能执行函数体代码。 核心规则:

  1. 实参的数量、类型需与形参严格匹配(可选参数、rest参数除外)。
  2. 函数调用时,实参会按顺序赋值给形参。
  3. 带返回值的函数,调用时可通过变量接收返回结果,也可直接调用(忽略返回结果)。
TypeScript 复制代码
// 定义函数:拼接两个字符串
function join(x: string, y: string): string {
  let z: string = `${x} ${y}`;
  return z;
}

// 方式1:接收返回值(推荐)
let res = join('hello', 'world');
console.info(res);   // 输出: hello world

// 方式2:直接调用,忽略返回结果。
join('Hi', 'ArkTS');
拓展:参数的传递方式

ArkTS中参数传递分为值传递引用传递,取决于参数的类型。

  • 值传递 :适用于基本类型(number、string、boolean、undefined、null),传递的是变量的副本,函数内修改副本不会影响原变量。
  • 引用传递 :适用于引用类型(对象、数组),传递的是变量的内存地址,函数内修改对象/数组的属性,会影响原变量。
TypeScript 复制代码
// 值传递(基本类型)
function changeNum(num: number) {
  num = 100;
}
let a = 10;
changeNum(a);
console.log(a);   // 输出:10(原变量未被修改)

// 引用传递(引用类型)
function changeObj(obj: {name: string}) {
  obj.name = 'ArkTS';
}
let person = {name: '鸿蒙'};
changeObj(person);
console.log(person.name);   // 输出:ArkTS(原对象被修改)

六、函数类型

ArkTS中函数也是一种数据类型,可通过type关键字定义函数类型 ,用于约束函数的参数列表返回类型最常用的场景是定义回调函数,让代码的类型约束更严格。

函数类型的定义语法
TypeScript 复制代码
type 函数类型名 = (参数1: 类型1, 参数2: 类型2, ...) => 返回类型;   // 语法格式
示例:定义回调函数
TypeScript 复制代码
// 定义函数类型:接收2个number类型参数,返回number类型结果。
type AddFunc = (a: number, b: number) => number;

// 定义函数,参数是AddFunc类型的回调函数。
function calculate(a: number, b: number, back: AddFunc) {
  return back(a, b);   // 调用回调函数 传入a和b
}

// 传入符合AddFunc类型的函数作为实参(求和)
const add = (x: number, y: number) => x + y;
console.log(calculate(2, 3, add));   // 输出:5(符合规矩 正常执行)

// 若传不符合规矩的函数(比如返回string),编译直接报错(这就是函数类型的作用!)。
const badAdd = (x: number, y: number) => '${x+y}';
calculate(2,3, badAdd);   // 报错:返回类型string不符合AddFunc的number类型
函数类型的赋值

定义函数类型后,可将符合该类型的函数赋值给变量,约束变量的函数形态。

TypeScript 复制代码
// 定义函数类型
type AddFunc = (a: number, b: number) => number;

// 定义符合该类型的函数
let add: AddFunc = (x, y) => x + y;

// 调用
console.log(add(1,2));   // 输出:3

七、箭头函数(Lambda函数)

箭头函数是普通函数的简洁写法,语法更精炼、代码更简洁,适合编写短小的函数逻辑,也是鸿蒙开发中高频使用的写法。

  • 核心特点:无自己的this(继承外层作用域的this)
1. 基本语法
TypeScript 复制代码
// 完整语法
let 函数名 = (形参1: 类型1, 形参2: 类型2) => {
  函数体;
  return 结果;
}

简写规则:

  1. 单表达式函数体,可省略大括号{}return
  2. 单个形参,可省略小括号()
  3. 无参或多个形参,必须保留小括号()
  4. 返回类型可省略,由编译器自动推断。
2. 常见使用形式
(1)无参箭头函数
TypeScript 复制代码
// 完整写法
let sayHi = () => {
  console.log('Hi, 箭头函数');
};
// 调用
sayHi();   // 输出:Hi,箭头函数

// 无参+单表达式(若有返回值)
let getStr = () => 'Hello Arrow Function';
console.log(getStr());   // 输出:Hello Arrow Function
(2)带参箭头函数
TypeScript 复制代码
// 多个形参完整写法
let multiply = (num1: number, num2: number): number => {
  return num1 * num2;
};
let res = multiply(5, 6);
console.log(res);   // 输出:30

// 单个形参简写(省略小括号、大括号、return)
let double = (n: number) => n * 2;   // 标准简写(推荐写法)
let double2 = n => n * 2;   // 不推荐写法

// 多个形参 单表达式 简写
let sum = (a: number, b: number) => a + b;
console.log(sum(3,4));   // 输出:7
3. 箭头函数的核心特性

箭头函数的核心差异是无自身的this,鸿蒙开发中在组件生命周期、事件回调中使用时需特别注意:

  1. 箭头函数的 this 继承自外层作用域,不会随调用方式改变。(外层无目标属性则输出undefined)
  2. 普通函数的 this 指向调用者 ,调用方式不同,this 指向不同。(调用者无目标属性也可能输出undefined)
  3. 箭头函数不能作为构造函数,不能使用new关键字调用。
TypeScript 复制代码
// 示例:箭头函数继承外层this
let obj = {
  name: 'ArkTS',
  fn1: function() {
    // 普通函数:this指向obj
    console.log(this.name);
  },
  fn2: () => {
    // 箭头函数:this继承外层(全局作用域)(无name属性)
    console.log(this.name);
  }
};
obj.fn1();   // 调用普通函数fn1  输出:ArkTS
obj.fn2();   // 调用箭头函数fn2  输出:undefined

八、闭包

闭包是由函数声明该函数的环境组合而成的整体,该环境包含了闭包创建时作用域内的所有局部变量。

  • 核心特性:闭包可以访问并保留外层函数的局部变量,即使外层函数执行完毕,局部变量也不会被销毁
1. 闭包的实操示例
TypeScript 复制代码
// 外层函数f
function f(): () => number {
  let count = 0;   // 外层函数的局部变量
  // 内层箭头函数g 形成闭包
  let g = (): number => { 
    count++;   // 访问外层函数的局部变量count
    return count; 
  };
  return g;   // 返回内层函数g
}

let z = f();   // 外层函数执行完毕 返回内层函数g
// 多次调用z 闭包保留count的状态 持续递增
console.log(z());   // 返回:1
console.log(z());   // 返回:2
console.log(z());   // 返回:3
2. 闭包的使用场景
  1. 封装私有变量:隐藏内部变量,仅通过闭包暴露操作方法,避免全局变量污染。
  2. 保留函数执行状态:如闭包实操示例中的计数器,多次调用可保留上一次的执行结果。
  3. 鸿蒙开发中:组件事件回调、定时器中保留上下文状态。
3. 闭包的注意事项

闭包会保留外层函数的变量,导致变量不会被垃圾回收 ,若过度使用或不当使用,会造成内存泄漏。 注意事项:

  1. 避免在循环中创建闭包。
  2. 不需要使用闭包时,及时解除引用(如将闭包变量赋值为null)。
4. 闭包封装私有变量示例
TypeScript 复制代码
// 封装计数器 仅暴露增/减方法 隐藏count变量
function createCounter() {
  let count = 0;   // 私有变量 外部无法访问
  return {
    add: () => count++,   // 闭包:增加计数
    sub: () => count--,   // 闭包:减少计数
    get: () => count      // 闭包:获取计数
  };
}

let counter = createCounter();
counter.add();
counter.add();
console.log(counter.get());   // 输出:2
counter.sub();
console.log(counter.get());   // 输出:1
// 外部无法直接修改count 避免变量污染

九、函数重载

函数重载指为同一个函数定义多个不同的签名(参数列表/返回类型不同) ,让同一个函数支持多种调用方式。 在ArkTS中编译器会根据实参的类型/数量,匹配对应的重载签名执行。

1. 函数重载的语法规则
  1. 先编写多个重载声明(同名、不同签名、无函数体)
  2. 最后编写一个函数实现(必须包含所有重载声明的参数/返回类型,用联合类型表示)。
  3. 重载声明的参数列表不能相同,否则编译报错。
  4. 函数实现的参数类型需覆盖所有重载声明的参数类型,返回类型也需匹配。
2. 函数重载的实操示例
TypeScript 复制代码
// 重载声明1:接收一个number类型参数 无返回值
function foo(x: number): void;

// 重载声明2:接收一个string类型参数 无返回值
function foo(x: string): void;

// 函数实现:参数类型为 " number | string "  覆盖所有重载声明
function foo(x: number | string): void {
  if (typeof x === 'number') {
    console.log('数字类型:', x);
  } else {
    console.log('字符串类型:', x);
  }
}

// 调用:编译器自动匹配对应的重载声明
foo(123);    // 匹配重载1  输出: 数字类型: 123
foo('aa');   // 匹配重载2  输出: 字符串类型: aa
3. 带返回值的函数重载示例
TypeScript 复制代码
// 重载声明1:两个number参数 返回number
function calc(a: number, b: number): number;

// 重载声明2:两个string参数 返回string
function calc(a: string, b: string): string;

// 函数实现
function calc(a: number | string, b: number | string): number | string {
  if (typeof a === 'number' && typeof b === 'number') {
    return a + b;
  } else {
    return `${a}${b}`;
  }
}

console.log(calc(1,2));   // 输出:3
console.log(calc('a','b'));   // 输出:ab
4. 函数重载的注意事项
  1. 函数重载仅在编译阶段生效,用于做类型校验,运行时只有一个函数实现。
  2. 不能只有重载声明而无函数实现,否则编译报错。
  3. 鸿蒙开发中,函数重载常用于封装通用方法,让方法支持多种参数类型,提升代码的灵活性。
相关推荐
UnicornDev7 天前
【HarmonyOS 6】底部悬浮导航的迷你栏适配(API23)
华为·harmonyos·arkts·鸿蒙
笔触狂放7 天前
【项目】基于ArkTS的老年人智能应用开发(1)
harmonyos·arkts·鸿蒙
UnicornDev9 天前
【HarmonyOS 6】底部悬浮导航的沉浸光感适配(API23)
华为·harmonyos·arkts·鸿蒙·鸿蒙系统
UnicornDev14 天前
【HarmonyOS 6】设置页面 UI 设计
ui·华为·harmonyos·arkts·鸿蒙
UnicornDev17 天前
【HarmonyOS 6】基于API23的底部悬浮导航
华为·harmonyos·arkts·鸿蒙·鸿蒙系统
积水成渊,蛟龙生焉17 天前
鸿蒙手势处理篇(滑动冲突、基础手势、组合手势)
华为·arkts·鸿蒙·滑动冲突·手势冲突·基础手势·组合手势
纯爱掌门人17 天前
聊聊 HarmonyOS 上的应用内通知授权弹窗
前端·harmonyos·arkts
UnicornDev20 天前
【HarmonyOS 6】练习记录页面 UI 设计
ui·华为·harmonyos·arkts·鸿蒙
哈__21 天前
新手入门harmonyOS开发:手把手教你用ArkTS实现一个天气应用
harmonyos·arkts
积水成渊,蛟龙生焉21 天前
鸿蒙装饰器V2详解
华为·harmonyos·arkts·鸿蒙·ark