【HarmonyOS应用开发入门】第三期:ArkTS语言基础(一)

学习鸿蒙开发就不得不学习ArkTs语言,ArkTs是HarmonyOS应用的默认开发语言,在TypeScript(简称TS)生态基础上做了扩展,保持TS的基本风格,接下来就和小鱼一起学习ArkTS语言吧。

一、ArkTS语言概述

1、ArkTS与TypeScript的关系

TypeScript提供了一种更结构化的JavaScript编码方法,ArkTS保持了TypeScript的大部分语法,现有的TypeScript开发者提供高度兼容的体验,帮助移动开发者快速上手。

2、ArkTS的核心特性:静态类型、装饰器、响应式

1)静态类型是ArkTS最重要的特性之一

对比静态类型 vs 动态类型,举个例子🌰 :快餐店点餐
动态类型店(像 JavaScript)
特点 :你说"我要一个汉堡",店员就给你随便做一个
优点 :点餐快,很灵活
风险:可能给你一个素汉堡,而你本来想吃牛肉汉堡

javascript 复制代码
// 就像这样
let 食物 = "汉堡";  // 现在它是字符串
食物 = 123;        // 突然变成了数字!
食物 = {肉: "牛肉"}; // 又变成了对象!
// 运行时才知道会发生什么

静态类型店(像 ArkTS)
特点:菜单上明确分类:

  • 🍔 牛肉汉堡:25元
  • 🥗 素汉堡:20元
  • 🍟 薯条:10元

流程:你点"牛肉汉堡",店员立即知道:

  1. 需要牛肉饼、面包、蔬菜
  2. 价格是25元
  3. 烹饪时间3分钟
javascript 复制代码
// ArkTS写法
let 食物: string = "牛肉汉堡";  // 一开始就确定类型
// 食物 = 123;  // 错误!编译器会说:"这里要的是食物,不是数字!"

总结:
静态类型 = 有详细图纸的建筑(提前规划,施工快,问题少)
动态类型 = 边想边建的房子(灵活,但容易出错,效率低)

2)装饰器

装饰器 = 不修改原代码,给类/方法/属性"添加功能"的特殊标记

举个例子🌰 : 🍰 蛋糕(原本的代码)

  • 🎂 加奶油(装饰器1:@奶油装饰)

  • 🍫 加巧克力(装饰器2:@巧克力装饰)

  • 🍓 加草莓(装饰器3:@草莓装饰)

最后变成一个豪华蛋糕!

ArkTs 有很多装饰器,@Component:组件装饰器、@State:状态装饰器、@Entry:入口装饰器,还可以自定义装饰器,以后的博文中再学习吧,先举个例子:

javascript 复制代码
@Entry
@Component
struct TabsExample {
  @State colorArray: [string, string][] =
    [['green', '#00CB87'], ['blue', '#007DFF'], ['yellow', '#FFBF00'], ['pink', '#E67C92']];
    ...
}

总结:装饰器就是 "不拆房子,只搞装修" 🏠 → 🏡

3)响应式:让UI"自动刷新"的魔法

举个例子🌰 :智能鱼缸 vs 普通鱼缸

🐠 普通鱼缸(非响应式)

你养了一缸鱼:

  • 水温25°C → 鱼很快乐 🐟
  • 水温降到20°C → 鱼不舒服,但你看不到变化

你必须:

  • 用手摸水
  • 看温度计
  • 手动更新鱼缸的显示牌

🐟 智能鱼缸(响应式)

  • 水温25°C → 鱼很快乐 🐟
  • 水温降到20°C → 鱼缸自动:
    🔴 灯光变红色
    📢 发出警报声
    📱 发送通知到手机
    所有变化自动发生!

总结:

一句话理解响应式:"牵一发而动全身,但不用你亲自去动" 🧵 → 👕

3、开发环境中的ArkTS支持

鸿蒙为ArkTS提供了一站式、智能化、高效能的开发环境,从编码到上架全链路支持

1)开发工具支持:DevEco Studio

✅ 智能代码提示(ArkTS专属)

✅ 实时预览(所见即所得)

✅ 一键调试(真机/模拟器)

✅ 性能分析(ArkTS内存/CPU监控)

✅ 热重载(修改代码即时生效)

✅ 组件可视化拖拽

2)语言支持

支持类型 具体内容 示例
语法高亮 ArkTS特有语法着色 @State、@Component 特殊颜色
智能补全 组件/API自动补全 输入Text( 自动提示属性
类型检查 静态类型实时验证 let a: string = 123 ❌ 立即报错
重构支持 重命名/提取组件等 右键 → Refactor → Extract Component
代码格式化 统一代码风格 Alt + Shift + F 自动格式化

3)调试与测试

javascript 复制代码
// 多层次调试支持
1、️ UI调试: 
   - 组件树查看器
   - 布局边界显示
   - 性能Overlay(FPS/内存)

️2、 代码调试:
   - 断点调试(ArkTS源码级)
   - 变量监视
   - 调用堆栈

️3、 测试框架:
   - 单元测试(ArkTS单元测试框架)
   - UI测试(自动化UI测试)
   - 性能测试(启动时间/流畅度)

4)、工程管理与构建

javascript 复制代码
// 项目结构支持
myApp/
├── entry/           # 主模块
│   ├── src/
│   │   ├── main/
│   │   │   ├── ets/         # ArkTS代码目录
│   │   │   │   ├── pages/   # 页面组件
│   │   │   │   ├── model/   # 数据模型
│   │   │   │   └── utils/   # 工具函数
│   │   │   └── resources/   # 资源文件
│   │   └── ohosTest/        # 测试代码
│   └── build-profile.json5  # 构建配置
├── build/           # 构建输出
└── oh-package.json5 # 依赖管理

二、基础类型

javascript 复制代码
// 基本类型
let name: string = "鸿蒙"
let age: number = 3
let isActive: boolean = true

// 数组类型
let numbers: number[] = [1, 2, 3]
let strings: Array<string> = ["a", "b", "c"]

// 元组类型
let tuple: [string, number] = ["鸿蒙", 2021]

// 枚举类型
enum Direction {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT"
}

三、变量声明与作用域

1、let与const的区别

🌰 比喻:租房 vs 买房

不管是北漂、深漂还是沪漂,有多少程序员拥有了const 房,同时拥有几十年的房贷,不敢失业不敢辞职,想想就扎心...言归正传,继续学习😭

🏠 let = 租房(可以搬家)

javascript 复制代码
let 我的地址 = "朝阳区101号";
console.log(我的地址); // "朝阳区101号"

// 可以随时搬家(重新赋值)
我的地址 = "海淀区202号";  // ✅ 没问题
我的地址 = "东城区303号";  // ✅ 继续搬家

🏡 const = 买房(地址固定)

javascript 复制代码
const 我的房子地址 = "朝阳区101号";
console.log(我的房子地址); // "朝阳区101号"

// 不能换地址(不能重新赋值)
我的房子地址 = "海淀区202号";  // ❌ 报错:Assignment to constant variable

📊 核心区别对比表

特性 let const
能否重新赋值
是否必须初始化 可以后赋值 必须
推荐使用场景 会变化的变量 不变的量

2、类型推断与类型注解

类型推断 vs 类型注解:让TS猜还是你告诉它?

🤖 类型推断:TS自动猜出类型,像智能助手

javascript 复制代码
// 你:我有个变量
let 价格 = 100;  // 没告诉类型

// TS助手:看到"100",自动推断:
// "哦,这是个数字!"
// 类型推断结果:let 价格: number

// 后续使用:
价格 = 200;      // ✅ OK
价格 = "免费";    // ❌ 错误!类型推断为number了

📝 类型注解:你明确告诉TS类型,像下详细指令

javascript 复制代码
// 你明确说:这是个字符串!
let 用户名: string = "夏小鱼";

// TS:收到!按字符串处理
// 后续使用:
用户名 = "本小鱼";      // ✅ OK
用户名 = 123;        // ❌ 错误!你说了是string的

📊 核心区别对比表

特性 类型推断 类型注解
谁决定类型 TypeScript编译器 开发者
代码量 少(不写类型) 多(写类型)
明确性 隐式 显式
使用场景 简单明显的情况 复杂或需要明确的情况

3、块级作用域与变量提升

🎪 块级作用域 vs 变量提升:变量的"活动范围"和"提前报名"

🌰 比喻:剧场里的座位:

🎭 块级作用域:分区管理

javascript 复制代码
// 整个剧场(全局作用域)
{
  // VIP区(块级作用域1)
  let vip = "夏小鱼";
  console.log(vip); // ✅ 能访问
}

{
  // 普通区(块级作用域2)  
  let normal = "赵小鱼";
  console.log(normal); // ✅ 能访问
}

// 剧场走廊(全局)
console.log(vip);    // ❌ 不能访问VIP区的客人
console.log(normal); // ❌ 不能访问普通区的客人

🎪 变量提升:提前占座

javascript 复制代码
console.log(vip); // 报错 Block-scoped variable 'vip' used before its declaration. <ArkTSCheck>
let vip = "夏小鱼";
javascript 复制代码
 // 1. 先把所有声明"提升"到最前面(占座)
    let vip:string;  // 提前声明(占座),值还没给
    // 2. 然后执行代码
    console.log(vip); // 报错Variable 'vip' is used before being assigned. <ArkTSCheck>
    vip = "夏小鱼";   // 现在才赋值

四、函数定义与使用

函数声明引入一个函数,包含其名称、参数列表、返回类型和函数体。

以下示例是一个简单的函数和它的语法语义说明:

  • 参数类型标注:a: number, b: number 显式声明参数类型为字符串类型。
  • 返回值类型:: number 指定函数返回值为字符串类型。
javascript 复制代码
// 函数声明
function add(a: number, b: number): number {
  let c: number = a + b ;
  return c;
}

可选参数函数:

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

可选参数的另一种形式,设置参数默认值

javascript 复制代码
function multiply(n: number, coeff: number = 2): number {
  return n * coeff;
}
multiply(2);  // 返回2*2
multiply(2, 3); // 返回2*3

rest参数

rest参数允许函数接收一个不定长数组,用于处理不定数量的参数输入。

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

sum(); // 返回0
sum(1, 2, 3); // 返回6

箭头函数

javascript 复制代码
let sum = (x: number, y: number): number => {
  return x + y;
}

函数重载

javascript 复制代码
function foo(x: number): void;            /* 第一个函数定义 */
function foo(x: string): void;            /* 第二个函数定义 */
function foo(x: number | string): void {  /* 函数实现 */
}

foo(123);     //  OK,使用第一个定义
foo('aa'); // OK,使用第二个定义

五、类与面向对象编程

类 = 设计蓝图

javascript 复制代码
// 基础类定义
export class User {
  // 属性
  id: string; // 用户ID
  login: string; // 登录用户名
  name?: string; // 显示名称
  avatar_url?: string; // 头像地址
  created_at?: string; // 注册时间
  html_url?: string; // GitHub主页地址

  // 构造方法
  constructor(id: string, login: string) {
    this.id = id;
    this.login = login;
  }
}

什么是面向对象编程OOP

面向对象 = 用现实世界的方式组织代码

  • 一切皆对象(Object)
  • 对象有属性(数据)和方法(行为)
  • 对象基于类(蓝图)创建

面向对象的四大支柱

1、封装

javascript 复制代码
export class User {
  // 属性
  id: string; // 用户ID
  login: string; // 登录用户名
  name?: string; // 显示名称
  avatar_url?: string; // 头像地址
  created_at?: string; // 注册时间
  html_url?: string; // GitHub主页地址

  constructor(id: string, login: string) {
    this.id = id;
    this.login = login;
  }

  // ------------ 方法
  // 获取显示名称
  get displayName(): string {
    return this.name || this.login || '匿名用户';
  }
}

2、继承

javascript 复制代码
export class LoginUser extends User {
  // 属性
  followers_url?: string; // 粉丝列表API地址
  type?: string; // 用户类型(User/Organization)
  url?: string; // API地址
  bio?: string; // 个人简介
  blog?: string; // 个人博客
  company?: string; // 公司
  email?: string; // 邮箱
  followers?: number; // 粉丝数
  following?: number; // 关注数
  top_languages?: string[]; // 最常用编程语言
  
  // 获取格式化粉丝数
  get formattedFollowers(): string {
    if (!this.followers) {
      return '0';
    }
    if (this.followers >= 1000) {
      return `${(this.followers / 1000).toFixed(1)}k`;
    }
    return this.followers.toString();
  }
}

3、多态:同样的接口,不同的实现

javascript 复制代码
interface Pay {
  pay(amount: number): boolean;
}

class AliPay implements Pay {
  pay(amount: number): boolean {
    console.log(`支付宝支付:${amount}元`);
    return true;
  }
}

class WechatPay implements Pay {
  pay(amount: number): boolean {
    console.log(`微信支付:${amount}元`);
    return true;
  }
}


class UnionPay implements Pay {
  pay(amount: number): boolean {
    console.log(`银联支付:${amount}元`);
    return true;
  }
}

// 使用时不用关心具体是哪种支付
function pay(amount: number, pay: Pay) {
  if (pay.pay(amount)) { // 多态调用
    console.log("支付成功!");
  }
}

4、抽象:定义规范,具体实现交给子类

javascript 复制代码
// 抽象类:不能直接创建对象,只能被继承
abstract class 图形 {
  // 抽象方法:只有声明,没有实现
  abstract 计算面积(): number;
  abstract 计算周长(): number;
  
  // 可以有具体方法
  显示信息(): void {
    console.log(`面积: ${this.计算面积()}, 周长: ${this.计算周长()}`);
  }
}

// 具体类:必须实现所有抽象方法
class 圆形 extends 图形 {
  constructor(private 半径: number) {
    super();
  }
  
  计算面积(): number {
    return Math.PI * this.半径 * this.半径;
  }
  
  计算周长(): number {
    return 2 * Math.PI * this.半径;
  }
}

class 矩形 extends 图形 {
  constructor(private 宽: number, private 高: number) {
    super();
  }
  
  计算面积(): number {
    return this.宽 * this.高;
  }
  
  计算周长(): number {
    return 2 * (this.宽 + this.高);
  }
}

// 使用
const 我的圆形 = new 圆形(5);
const 我的矩形 = new 矩形(4, 6);

我的圆形.显示信息();  // "面积: 78.54..., 周长: 31.41..."
我的矩形.显示信息();  // "面积: 24, 周长: 20"

// const 抽象图形 = new 图形();  // ❌ 错误!抽象类不能实例化

六、接口与泛型

接口已经在面向对象的多态中写了代码啦:interface Pay,

1、🔌 接口 = 插座标准

javascript 复制代码
// 接口定义了一个"标准",不管什么设备都要符合这个标准才能插电
interface 电源插座 {
  电压: number;     // 必须是220V
  插孔类型: string;  // 必须是三孔
  有地线: boolean;   // 必须有地线
}

// 任何设备要实现这个接口,都必须满足这些要求
class 电视机 implements 电源插座 {
  电压: number = 220;
  插孔类型: string = "三孔";
  有地线: boolean = true;
  品牌: string = "索尼";
  
  开机() {
    console.log("电视机开机");
  }
}

class 空调 implements 电源插座 {
  电压: number = 220;
  插孔类型: string = "三孔";
  有地线: boolean = true;
  功率: number = 2000;
  
  制冷() {
    console.log("空调开始制冷");
  }
}

// 电源接口检查
function 检查电器安全(电器: 电源插座): boolean {
  return 电器.电压 === 220 && 电器.有地线;
}

// 任何实现了电源接口的电器都可以使用这个函数
const 我的电视 = new 电视机();
const 我的空调 = new 空调();

console.log(检查电器安全(我的电视));  // ✅ true
console.log(检查电器安全(我的空调));  // ✅ true

2、🧱 泛型 = 万能模具

javascript 复制代码
// 泛型就像一个"万能模具",可以制造各种形状的东西
class 盒子<T> {  // T是类型参数,像模具的形状参数
  内容: T;
  
  constructor(内容: T) {
    this.内容 = 内容;
  }
  
  获取内容(): T {
    return this.内容;
  }
  
  更换内容(新内容: T): void {
    this.内容 = 新内容;
  }
}

// 用同一个模具制造不同形状的东西
const 数字盒子 = new 盒子<number>(100);        // T = number
const 字符串盒子 = new 盒子<string>("hello");   // T = string
const 对象盒子 = new 盒子<{name: string}>({ name: "小明" });

console.log(数字盒子.获取内容());    // 100 (类型是number)
console.log(字符串盒子.获取内容());  // "hello" (类型是string)

// 类型安全!
数字盒子.更换内容(200);        // ✅ 正确
// 数字盒子.更换内容("文本");   // ❌ 错误!必须是number

📊 核心区别对比表

特性 接口 范型
作用 定义标准 创建可复用的类型
关注点 结构/形状 类型参数化
使用场景 多态、代码约束 容器、工具函数、复用逻辑

七、实践任务

1、基础任务

根据搜索用户接口文档:https://docs.atomgit.com/docs/apis/get-api-v-5-search-users

创建AtomGit 的用户类,包含id,login,name,avatar_url,created_at,html_url属性;其中name,avatar_url,created_at,html_url为可选参数

实现用户名显示方法disPlayName,login和name都为空显示"匿名用户"

有没有发现答案已经在前面的博文里面啦,找不到的留言小鱼帮你一起进步!

2、进阶任务

根据获取一个用户接口文档:https://docs.atomgit.com/docs/apis/get-api-v-5-users-username

创建一个用户类,并格式化粉丝数

javascript 复制代码
export class LoginUser extends User {
  // 属性
  followers_url?: string; // 粉丝列表API地址
  type?: string; // 用户类型(User/Organization)
  url?: string; // API地址
  bio?: string; // 个人简介
  blog?: string; // 个人博客
  company?: string; // 公司
  email?: string; // 邮箱
  followers?: number; // 粉丝数
  following?: number; // 关注数
  top_languages?: string[]; // 最常用编程语言

  // 获取格式化粉丝数
  get formattedFollowers(): string {
    if (!this.followers) {
      return '0';
    }
    if (this.followers >= 1000) {
      return `${(this.followers / 1000).toFixed(1)}k`;
    }
    return this.followers.toString();
  }
}

又是完美的一天 🎉

相关推荐
子榆.4 小时前
Flutter 与开源鸿蒙(OpenHarmony)国际化与无障碍适配指南:打造真正包容的跨平台应用
flutter·华为·开源·harmonyos
子榆.4 小时前
Flutter 与开源鸿蒙(OpenHarmony)深度集成:从原理到实战进阶
flutter·华为·开源·harmonyos
二流小码农4 小时前
鸿蒙开发:个人开发者如何使用华为账号登录
android·ios·harmonyos
江澎涌5 小时前
鸿蒙 SDK 发布实战:JWorker 上架 ohpm 全流程
typescript·harmonyos·arkts
子榆.5 小时前
Flutter 与开源鸿蒙(OpenHarmony)的融合:跨平台开发新纪元
flutter·华为·开源·harmonyos
全球通史6 小时前
HarmonyOS机械臂蓝牙控制应用开发完整教程
华为·harmonyos
爱吃大芒果6 小时前
Flutter 表单开发实战:表单验证、输入格式化与提交处理
开发语言·javascript·flutter·华为·harmonyos
狮子也疯狂6 小时前
跨平台适配:Flutter在鸿蒙生态中的应用
flutter·华为·harmonyos
不爱吃糖的程序媛7 小时前
Flutter-OH OAuth 鸿蒙平台适配详细技术文档
javascript·flutter·harmonyos