跟着坚果派社区从零开始学鸿蒙——ArkTS模块系统全解析:组织代码的艺术
🧩 ArkTS模块系统全解析:组织代码的艺术 🧩
💫 干货分享! 模块化是现代应用开发的基石,掌握ArkTS的模块系统能让你的代码结构更清晰、更易维护。今天就带大家深入了解这个强大的特性~
📌 模块的基本概念:代码的组织单元
模块是程序的基本组织单元,每个模块都有自己的作用域。在模块中创建的声明(变量、函数、类等)在该模块之外默认是不可见的,除非它们被显式导出。这种机制有效地避免了命名冲突,并帮助我们组织大型应用程序。
📌 导出:分享你的代码
🔸 导出声明
使用export
关键字可以导出顶层声明,使其在其他模块中可用:
// geometry.ts
export class Point {
x: number = 0;
y: number = 0;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
export let Origin = new Point(0, 0);
export function Distance(p1: Point, p2: Point): number {
return Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
}
🔸 默认导出
使用export default
可以指定模块的默认导出,每个模块只能有一个默认导出:
// demo.ts
class Demo {
constructor() {
// 初始化逻辑
}
sayHello(): void {
console.info("Hello from Demo!");
}
}
export default new Demo(); // 导出Demo类的实例作为默认导出
📌 导入:使用其他模块的代码
🔸 静态导入
静态导入是在模块顶部声明的,在代码执行前就确定了依赖关系。有几种不同的导入方式:
1️⃣ 导入整个模块
// 导入整个模块,并使用命名空间访问其导出
import * as Utils from './utils';
Utils.X; // 访问utils模块导出的X
Utils.Y; // 访问utils模块导出的Y
2️⃣ 导入特定的导出
// 只导入需要的特定导出
import { X, Y } from './utils';
X; // 直接使用X
Y; // 直接使用Y
3️⃣ 导入并重命名
// 导入并重命名,避免命名冲突
import { X as Z, Y } from './utils';
Z; // 使用Z访问utils模块的X
Y; // 直接使用Y
// X; // 错误:X不可见
4️⃣ 导入默认导出
// 导入默认导出
import demo from './demo';
demo.sayHello(); // 输出: Hello from Demo!
🔸 动态导入
动态导入允许根据条件或按需加载模块,它返回一个Promise:
// Calc.ts
export function add(a: number, b: number): number {
let c = a + b;
console.info('Dynamic import, %d + %d = %d', a, b, c);
return c;
}
// Index.ts
// 使用动态导入
import("./Calc").then((obj) => {
console.info(obj.add(3, 5)); // 输出: Dynamic import, 3 + 5 = 8 然后输出 8
}).catch((err) => {
console.error("Module dynamic import error: ", err);
});
在异步函数中,可以使用await
简化动态导入:
// say.ts
export function hi() {
console.info('Hello');
}
export function bye() {
console.info('Bye');
}
// 在异步函数中使用动态导入
async function test() {
let ns = await import('./say');
ns.hi(); // 输出: Hello
ns.bye(); // 输出: Bye
// 也可以解构导入的模块
let { hi, bye } = await import('./say');
hi(); // 输出: Hello
bye(); // 输出: Bye
}
test();
🔸 导入HarmonyOS SDK的开放能力
HarmonyOS SDK提供了丰富的开放能力,可以通过导入相应的模块来使用:
1️⃣ 直接导入接口模块
import UIAbility from '@ohos.app.ability.UIAbility';
2️⃣ 通过Kit导入单个模块
import { UIAbility } from '@kit.AbilityKit';
3️⃣ 通过Kit导入多个模块
import { UIAbility, Ability, Context } from '@kit.AbilityKit';
4️⃣ 导入Kit的所有模块
import * as abilityKit from '@kit.AbilityKit';
// 使用导入的模块
let ability = new abilityKit.UIAbility();
⚠️ 注意:导入Kit的所有模块可能会导入过多无需使用的模块,导致编译后的HAP包太大,占用过多资源,请谨慎使用。
📌 顶层语句:模块的直接执行代码
顶层语句是指在模块最外层编写的语句,不被任何函数、类或块级作用域包裹。这些语句在模块加载时会直接执行。
// logger.ts
console.info("Logger module loaded"); // 顶层语句,模块加载时执行
export function log(message: string): void {
console.info(`[LOG]: ${message}`);
}
// 导入logger.ts时,会输出"Logger module loaded"
📌 关键字this:上下文引用
在ArkTS中,this
关键字只能在类的实例方法中使用,它指向:
- 调用实例方法的对象
- 正在构造的对象(在构造函数中)
class Counter {
count: number = 0;
increment(): void {
this.count++; // this指向Counter的实例
}
constructor(initialValue: number) {
this.count = initialValue; // this指向正在构造的对象
}
}
⚠️ 使用限制:
- 不支持this类型
- 不支持在函数和类的静态方法中使用this
class A {
n: number = 0;
f1(arg1: this) {} // 错误:不支持this类型
static f2(arg1: number) {
this.n = arg1; // 错误:不支持在类的静态方法中使用this
}
}
function foo(arg1: number) {
this.n = arg1; // 错误:不支持在函数中使用this
}
📌 注解:元数据的力量
注解(Annotation)是一种特殊的语言特性,它通过添加元数据来改变应用声明的语义。在ArkTS中,注解以@
符号开头。
🔸 注解的声明与使用
// 声明注解
@interface ClassAuthor {
authorName: string
}
// 使用注解
@ClassAuthor({authorName: "Bob"})
class MyClass {
// 类的实现
}
🔸 注解字段的类型限制
注解字段仅限于以下类型:
- number
- boolean
- string
- 枚举
- 以上类型的数组
@interface DocumentInfo {
title: string;
version: number = 1;
isPublic: boolean = true;
tags: string[] = [];
status: DocumentStatus; // 枚举类型
}
enum DocumentStatus {
DRAFT,
REVIEW,
PUBLISHED
}
🔸 注解的使用规则
- 注解必须放置在声明之前
- 注解名称必须以
@
为前缀,且@
和名称之间不允许有空格 - 多个注解可以应用于同一个声明
- 当前仅允许对类声明和方法声明使用注解
@ClassPreamble({authorName: "John", revision: 2})
@MyAnno() // 多个注解应用于同一个类
class MyClass {
@MethodAnno({data: 123})
foo(): void {
// 方法实现
}
@MethodAnno({data: 456})
static bar(): void {
// 静态方法实现
}
}
🔸 注解的导入导出
注解也可以被导入导出:
// annotations.ts
export @interface MyAnno {}
export @interface ClassAuthor {
name: string;
}
// app.ts
import { MyAnno } from './annotations';
import * as anno from './annotations';
@MyAnno
@anno.ClassAuthor({name: "Alice"})
class App {
// 类的实现
}
🔸 注解的限制
- 不允许在抽象类或抽象方法上使用注解
- 不允许在类的getter和setter方法中添加注解
- 同一个实体不能重复使用同一注解
- 子类不会继承基类的注解
// 错误示例
@MyAnno // 错误:不允许在抽象类上使用注解
abstract class Base {
@MyAnno // 错误:不允许在抽象方法上使用注解
abstract foo(): void;
}
class Child extends Base {
// 子类不会继承基类的注解
foo(): void {
// 实现
}
}
💡 模块化编程的最佳实践
- 单一职责原则:每个模块应该只负责一个功能或相关功能的集合
- 明确的导出:只导出模块的公共API,保持内部实现的私有性
- 避免循环依赖:模块之间的循环依赖会导致难以理解和维护的代码
- 合理使用动态导入:对于大型依赖或条件加载的模块,使用动态导入提高应用性能
- 组织模块结构:按功能、特性或层次组织模块,使项目结构清晰
🌈 模块化的应用场景
🔸 功能模块化
将不同功能拆分为独立模块:
// auth.ts - 认证相关功能
export function login(username: string, password: string): boolean {
// 实现登录逻辑
return true;
}
// user.ts - 用户相关功能
import { login } from './auth';
export class User {
// 用户相关实现
}
🔸 UI组件模块化
将UI组件封装为独立模块:
// button.ts - 按钮组件
export class Button {
// 按钮组件实现
}
// dialog.ts - 对话框组件
export class Dialog {
// 对话框组件实现
}
// app.ts - 应用主模块
import { Button } from './button';
import { Dialog } from './dialog';
// 使用组件
🔸 服务模块化
将后端服务封装为独立模块:
// api.ts - API服务
export async function fetchData(url: string): Promise<any> {
// 实现数据获取逻辑
}
// cache.ts - 缓存服务
export class Cache {
// 缓存实现
}
// app.ts - 应用主模块
import { fetchData } from './api';
import { Cache } from './cache';
// 使用服务
💫 小结: ArkTS的模块系统为我们提供了强大的代码组织工具,通过导入导出机制,我们可以构建模块化、可维护的应用程序。结合注解特性,可以为代码添加丰富的元数据,进一步增强代码的表达能力。
❤️ 如果觉得有用,请点赞收藏,你的支持是我持续创作的动力!
#编程学习 #ArkTS #模块化编程 #HarmonyOS #技术干货 #前端开发
更多推荐
所有评论(0)