写点什么

【HarmonyOS NEXT】ArkTs 模块的导出和引入

作者:冉冉同学
  • 2024-12-20
    山东
  • 本文字数:5270 字

    阅读完需:约 17 分钟

【HarmonyOS NEXT】ArkTs 模块的导出和引入

1. 前置学习文档

2.前言

什么是模块?

模块可以理解为函数代码块的功能,是封装对象的属性和方法的 javascript 代码,它可以是某单个文件,变量或者函数


  历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,这对开发大型的、复杂的项目形成了巨大障碍。


  在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD/CMD 三种。前者用于服务器,后者用于浏览器。ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD/CMD 规范,成为浏览器和服务器通用的模块解决方案。


  ES6 之后,官方制定了模块规范**【ES6 Module】** —— ES6 标准规范中,以 export 指令导出接口,以 import 引入模块,ArkTS 中的模块化也是基于此规范来实现的


关于更多关于前端模块化信息可以看这篇文章:https://mp.weixin.qq.com/s/15sedEuUVTsgyUm1lswrKA

3. export命令

关于 export 命令的详细文档介绍:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/export

3.1 导出单个[类/函数/变量]

下面是一个 ets[arkts]文件,里面使用 export 命令来导出变量,函数或类(class)


//A.ets​//导出变量​export let str = "export的内容";​//导出函数​export function add(x: number, y: number) {​  return x + y;​}​//导出类​export class Test {​  printHello() {​    console.log("你好 世界")​  }​}
复制代码

3.2 导出列表[推荐写法]

除了上述的写法,还有一种推荐使用的,因为这样就可以在脚本尾部,一眼看清楚输出了哪些变量。


//A.ets​let str = "export的内容";​function add(x: number, y: number) {​  return x + y;​}​class Test {​  printHello() {​    console.log("你好 世界")​  }​}​//导出变量、函数、类​export {str,add,Test}
复制代码

3.3 导出别名/重命名

通常情况下,export 输出的变量就是本来的名字,但是可以使用 as 关键字重命名。


//A.ets​let str = "export的内容";​function add(x: number, y: number) {​  return x + y;​}​class _Test {​  printHello() {​    console.log("你好 世界")​  }​}​let test=new Test()​//导出变量、函数、类,并重命名​export {​  str as Str, add as Add, Test as TT​}
复制代码

4. import命令

关于 import 命令的详细文档介绍:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/import


使用 export 命令定义了模块的对外接口以后,其他 【ets/ts/js】 文件就可以通过 import 命令加载这个模块。


**📢 单例模式:**import 模块的代码只会执行一次,同一个 url 文件只会第一次导入时执行代码。后续任何地方 import 都不会执行模块代码了,也就是说,import 语句是 Singleton 模式的。


**📢 只读-共享:**模块导入的接口的是只读的,不能修改。当然引用对象的属性值是可以修改的,不建议这么干,注意模块是共享的,导出的是一个引用,修改后其他方也会生效。

4.1 引入导出的内容

  使用 export 命令定义了模块的对外接口以后,其他 JS 文件就可以通过 import 命令加载这个模块。


下面代码的 import 命令,用于加载 A.ets 文件,引入后便可以在 B.ets 文件中使用 A.ets 文件中的变量、函数或类等。import 命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(A.ets)对外接口的名称相同。


//A.ets​let str = "export的内容";​function add(x: number, y: number) {​  return x + y;​}​class Test {​  printHello() {​    console.log("你好 世界")​  }​}​//导出变量、函数、类,并重命名​export {​  str as Str, add as Add, Test as TT​}​//B.ets​import { Str, Add, TT } from './A';​class Test {​  print() {​    let string = Str //使用导出的变量​    let number = Add(0, 1) //使用导出的方法​    let class = new TT() //使用导出的类​  }​}​//也可以分开写两次,导入的时候带花括号,将每个变量函数名写清楚​import { Str } from './A';​import { Add} from './A';​import { TT } from './A';​//但是不能重复导入相同的,例如下面的例子​import { TT } from './A';​import { TT } from './A';
复制代码

4.2 引入别名/重命名

如果想为输入的变量重新取一个名字,import 命令要使用 as 关键字,将输入的变量重命名。


//A.ets​let str = "export的内容";​function add(x: number, y: number) {​  return x + y;​}​class Test {​  printHello() {​    console.log("你好 世界")​  }​}​//导出变量、函数、类,并重命名​export {​  str as Str, add as Add, Test as TT​}​//B.ets​import { Str as Str2, Add as Add2, TT as TT2 } from './A';​class Test {​  print() {​    let string = Str2 //使用导出的变量​    let number = Add2(0, 1) //使用导出的方法​    let class = new TT2() //使用导出的类​  }​}​
复制代码

4.3 批量引入

有的时候我们发现如果一个模块里面有多个导出的[类/函数/变量],使用的时候发现需要一个一个声明,比较繁琐,此时就可以使用 import * as name 语法,该语法可以导入所有导出接口,即导入模块整体


建议按需导出,不用,这样有利于构建工具的优化,剔除没用到的代码。*


//B.ets​import  * as moduleA  from './A';​class Test {​  print() {​    let zoo = new moduleA.Zoo()//使用非默认导出的类​    zoo.printZoo()​    let string = moduleA.Str //使用非默认导出的变量​    let number = moduleA.Add(0, 1) //使用非默认导出的方法​    let tt2 = new moduleA.TT() //使用非默认导出的类​  }​}
复制代码

5. export default 命令

export default 命令用于指定模块的默认输出,一个模块只能有一个默认输出,因此 export default 命令只能使用一次。

所以,import 命令后面才不用加大括号,因为只可能唯一对应 export default 命令。一个文件内不能有多个 export default,另外,import 的时候, 还可以起任何变量名表示引入变量

5.1 导出默认变量

//A.ets​export default "export的内容"​//或者可以声明一个变量,然后在导出这个变量​const xxx="export的内容"​export default xxx​//B.ets​import str from './A';​class Test {​  print() {​    let string = str //使用导出的变量​  }​}
复制代码

5.2 导出默认函数

//A.ets​export default function() {​  console.log('我是默认函数');​}​//或者还可以声明一个函数,然后导出这个函数 【推荐写法】​let add= (x: number, y: number) => {​  return x + y;​}​export default add​//或者还可以这样写​function add(x: number, y: number) {​  return x + y;​}​//等同于 export default add;​export {add as default};​//B.ets​import func from './A';​class Test {​  print() {​    let string = func(0, 1)//使用导出的方法​  }​}
复制代码

5.3 导出默认类

//A.ets​export default class Test {​  printHello() {​    console.log("你好 世界")​  }​}​//或者还可以声明一个类,然后导出这个类​class Test {​  printHello() {​    console.log("你好 世界")​  }​}​export default Test​//B.ets​import Classics from './A';​class Test {​  print() {​    let classics = new Classics()​    classics.printHello()​  }​}
复制代码

5.4 导出默认模块+非默认模块

//A.ets​let str = "export的内容";​function add(x: number, y: number) {​  return x + y;​}​class Test {​  printHello() {​    console.log("你好 世界")​  }​}​export class Zoo {​  printZoo() {​    console.log("你好 大象")​  }​}​export {​  str as Str, add as Add, Test as TT​}​export default Test​//B.ets​import Classics, { Str as Str2, Add as Add2, TT as TT2, Zoo } from './A';​class Test {​  print() {​    let classics = new Classics()//使用默认导出的类​    classics.printHello()​  }​}
复制代码

5.5 批量导出

  这种场景在使用 ArkTS 中的 hsp 模块时非常有用。可能被多个业务 module 使用的 har 库,可以使用 hsp 模块进行管理,然后使用 hsp 进行批量导出 har 对外暴露的模块.


//A.ets​let str = "export的内容";​function add(x: number, y: number) {​  return x + y;​}​class Test {​  printHello() {​    console.log("你好 世界")​  }​}​export class Zoo {​  printZoo() {​    console.log("你好 大象")​  }​}​export {​  str as Str, add as Add, Test as TT​}​export default Test​//B.ets​export * from './A';​//C.ets​import * as ModuleA  from './B';​class Test {​  print() {​    let zoo = new ModuleA.Zoo()//使用非默认导出的类​    zoo.printZoo()​    let string = ModuleA.Str //使用非默认导出的变量​    let number = ModuleA.Add(0, 1) //使用非默认导出的方法​    let tt2 = new ModuleA.TT() //使用非默认导出的类​  }​}
复制代码

6. 一些常见模块化导出和引入的写法

6.1 写法 1 [默认写法]

//Person.ets​class _Person {​  age: number​  constructor() {​    this.age = 18​  }​  getAge(): number {​    return this.age​  }​}​const Person = new _Person();​export default Person;​import Person from './Person.ets'​Person.age​Person.getAge()
复制代码

6.2 写法 2[默认写法]

//Person.ts​export default {​  age: 0,​  getAge(): number {​    return this.age​  }​};​import Person from './Person.ts'​Person.age​Person.getAge()
复制代码

6.3 写法 3 [别名写法]

//Person.ets​export let age = 0;​export function getAge(): number {​  return age​}​import * as Person from './Person.ets'​Person.age​Person.getAge()
复制代码

6.4 写法 4 [分组批量导出写法]

这个方法的好处是不用再维护 library 的 index.ets ,只需要维护要导出模块文件夹下的 index.ets 即可


//【1】批量导出login 模块下的所有方法​// 1.1、src/main/ets/login/Login.ets​export class Login​{​}​export class PwdLogin​{​}​//1.2、src/main/ets/login/index.ets​export  * from './Login'​//【2】批量导出login 模块下的所有方法​// 2.1、src/main/ets/login/Login.ets​export class Register​{​}​export class RegisterPwd​{​}​//2.2、src/main/ets/login/index.ets​export  * from './Register'​//【3】批量导出所有模块下的所有方法 ​//3.1 src/index.ets​export * from './src/main/ets/login'​
复制代码

7. 疑问

7.1 为什么 export default 只能有一个

  • 因为 export default 本质上是别名【as】的语法糖

  • 本质上,下面的,A.ets 文件的 export default 输出一个叫做 default 的变量,然后系统允许你为它取任意名字。 自然 default 只能有一个值,所以一个文件内不能有多个 export default。


// A.ets​// 导出函数​export default function() {}​// 等效于:​function a() {};​export {a as default};​//B.ets​import a from './A'; // a 是 {defalut as a}的替代写法。​//另外一个例子​//A.ets​let a = 1;​let b = 2;​export { a };​export default b;​//B.ets​import * as all from "./A";​console.log(JSONUtils.bean2Json(all)) //输出 {"a":1,"default":2}
复制代码

7.2 导出 new Class(),内存引用是否是一个?

  • 因为 ES6 模块输出的是值的引用,所以如果 export new class,则多个位置引用的其实是相同的 class 实例


//MyClass.ets​class MyClass {​    count: number​    constructor() {​        this.count = 0;​    }​    increment():number {​        this.count++;​        return this.count​    }​}​// 导出类的对象​export const obj = new MyClass();​//Test.est​import { obj as objA } from './TestClass' new MyClass();​import { obj as objB } from './TestClass' new MyClass();​console.log(objA.increment() + "")​console.log(objB.increment() + "")​因为export 输出的是值的引用,所以此处输出的是​1​2​而不是​1​1
复制代码


发布于: 刚刚阅读数: 2
用户头像

冉冉同学

关注

还未添加个人签名 2018-05-12 加入

还未添加个人简介

评论

发布
暂无评论
【HarmonyOS NEXT】ArkTs 模块的导出和引入_鸿蒙_冉冉同学_InfoQ写作社区