第三章 ArkTS语言基础(上):语法概览、变量声明与类型系统、函数定义与高阶函数

好,咱们开始进入ArkTS语言基础部分。说实话,很多同学一上来就急着写界面、调接口,结果代码写得乱七八糟,后面维护起来想哭。我个人习惯是,先把语言基础打扎实,后面写代码就像搭积木一样顺畅。

ArkTS是鸿蒙应用开发的主力语言。它基于TypeScript,但针对鸿蒙系统做了不少优化。说白了,你如果会TypeScript,上手ArkTS会很快。但如果你只会JavaScript,嗯,有几个坑我得提前给你指出来。

3.1 ArkTS语法概览

先看一个最简单的ArkTS程序长什么样:

@Entry
@Component
struct HelloWorld {
    build() {
        Column() {
            Text('Hello, HarmonyOS!')
                .fontSize(30)
                .fontColor(Color.Blue)
        }
        .padding(20)
    }
}

看到没?结构很清晰。@Entry@Component是装饰器,告诉系统这是个页面组件。build()方法里写UI布局。ArkTS的语法风格偏向声明式,你描述“要什么”,而不是“怎么画”。

小提示:ArkTS的装饰器语法是它的特色。我在项目中遇到过不少新手把装饰器写错位置,导致编译报错。记住:装饰器紧跟在目标声明之前,中间不能有空行。

3.2 变量声明与类型系统

变量声明这块,ArkTS和TypeScript基本一致。但有几个细节我得强调一下。

3.2.1 let、const 与 var

在ArkTS中,我建议你只用letconstvar虽然能用,但它的作用域规则容易出问题。你想想看,一个变量在函数里声明了,结果在函数外还能访问到,这多吓人?

// 推荐写法
let count: number = 0
const appName: string = '车载导航'

// 不推荐
var oldWay = '别这么写'

const声明的是常量,一旦赋值就不能再改。但要注意,如果常量是对象,对象内部的属性还是可以改的。嗯,这里是个小坑。

3.2.2 类型系统

ArkTS是强类型语言。这意味着每个变量都有明确的类型。为什么要强类型?说白了,就是让编译器帮你提前发现错误。我在项目里见过太多因为类型不匹配导致的运行时崩溃了。

基础类型包括:

类型 说明 示例
number 数字,包括整数和浮点数 let age: number = 25
string 字符串 let name: string = '车载'
boolean 布尔值 let isRunning: boolean = true
undefined 未定义 let x: undefined = undefined
null 空值 let y: null = null

还有更复杂的类型,比如数组、对象、联合类型等。举个例子:

// 数组
let list: number[] = [1, 2, 3]
let list2: Array<string> = ['a', 'b', 'c']

// 对象类型
interface CarInfo {
    brand: string
    speed: number
    isElectric: boolean
}

let myCar: CarInfo = {
    brand: '鸿蒙汽车',
    speed: 120,
    isElectric: true
}

// 联合类型
let id: number | string = 'ABC123'
重点:类型系统是ArkTS的基石。你写的每个变量、每个函数参数、每个返回值,最好都明确标注类型。这看起来麻烦,但能帮你省下大量调试时间。

3.2.3 类型推断

ArkTS也能自动推断类型。比如:

let message = 'Hello'  // 自动推断为 string 类型
let count = 42         // 自动推断为 number 类型

但我不建议过度依赖类型推断。特别是函数返回值,显式标注类型能让代码更清晰。我曾经接手过一个项目,函数返回值全靠猜,那叫一个痛苦。

3.3 函数定义与高阶函数

函数是代码组织的基本单元。ArkTS的函数定义方式很灵活,咱们一个一个看。

3.3.1 函数定义

最基本的函数定义:

// 普通函数
function add(a: number, b: number): number {
    return a + b
}

// 箭头函数
const multiply = (x: number, y: number): number => {
    return x * y
}

// 可选参数
function greet(name: string, greeting?: string): string {
    if (greeting) {
        return `${greeting}, ${name}!`
    }
    return `Hello, ${name}!`
}

// 默认参数
function createCar(brand: string, speed: number = 100): void {
    console.log(`创建了一辆${brand},速度${speed}km/h`)
}

注意那个?:语法,表示参数是可选的。调用时可以不传。默认参数就更方便了,不传就用默认值。

3.3.2 高阶函数

高阶函数,说白了就是“函数里面用函数”。要么接收函数作为参数,要么返回一个函数。这个概念在ArkTS里非常常用。

举个例子,车载应用里经常要处理列表数据:

// 高阶函数:map
const speeds: number[] = [60, 80, 100, 120]
const speedLimits = speeds.map(s => s * 1.1)  // 每个速度增加10%
console.log(speedLimits)  // [66, 88, 110, 132]

// 高阶函数:filter
const fastCars = speeds.filter(s => s > 80)
console.log(fastCars)  // [100, 120]

// 高阶函数:reduce
const totalSpeed = speeds.reduce((acc, cur) => acc + cur, 0)
console.log(totalSpeed)  // 360

你想想看,如果没有高阶函数,你得写多少循环?代码又长又容易出错。高阶函数让数据处理变得优雅。

避坑指南:我曾经在项目里用高阶函数时,忘了处理空数组的情况。结果reduce直接报错。记住:使用reduce时,一定要给初始值。比如上面的0就是初始值。

3.3.3 自定义高阶函数

你也可以自己写高阶函数。比如车载系统里经常要记录操作日志:

// 自定义高阶函数:日志装饰器
function withLogging(fn: Function): Function {
    return function(...args: any[]) {
        console.log(`调用函数:${fn.name},参数:`, args)
        const result = fn(...args)
        console.log(`函数返回:`, result)
        return result
    }
}

// 使用
function calculateDistance(speed: number, time: number): number {
    return speed * time
}

const loggedCalculate = withLogging(calculateDistance)
loggedCalculate(60, 2)  // 会打印日志

这个模式在鸿蒙开发里很实用。比如你想给所有按钮点击事件加上埋点,用高阶函数包装一下就行,不用每个按钮都写一遍埋点代码。

3.4 实际项目中的经验

最后分享几个我在车载项目里踩过的坑:

  • 类型断言要谨慎:有时候你觉得某个变量肯定是某个类型,就用as断言。但运行时如果类型不对,程序直接崩溃。能用类型守卫就用类型守卫。
  • 箭头函数的this:箭头函数不绑定自己的this,它会捕获外层上下文的this。这在回调函数里特别有用。但如果你用普通函数,this可能会指向undefined。
  • 函数重载:ArkTS支持函数重载,但写法有点特殊。同一个函数名,写多个类型签名,最后写实现。我建议新手先别碰这个,容易搞混。
我的习惯:写函数时,先想清楚输入输出类型,再写实现。这样代码结构清晰,也方便别人阅读。记住:好的代码是自文档化的。

好了,这一章的内容就到这里。ArkTS的语法基础是后面所有内容的地基。你把这些概念吃透了,后面写UI组件、处理状态管理、调用系统API,都会顺手很多。下一章咱们继续深入,聊聊ArkTS的面向对象编程和模块化。