鸿蒙ArkTS语言学习(四):泛型&空安全&模块导入导出 ...

打印 上一主题 下一主题

主题 536|帖子 536|积分 1608

泛型与函数

泛型类型和函数允许创建的代码在各种类型上运行,而不仅支持单一类型。
泛型类和接口(Element)

类和接口可以定义为泛型,将参数添加到类型定义中,如以下示例中的类型参数Element:
  1. class CustomStack<Element> {
  2.   public push(e: Element):void {
  3.     // ...
  4.   }
  5. }
复制代码
要使用类型CustomStack,必须为每个类型参数指定类型实参:
  1. let s = new CustomStack<string>();
复制代码
编译器在使用泛型类型和函数时会确保类型安全。
泛型约束

泛型类型的类型参数可以被限制只能取某些特定的值。例如,MyHashMap<Key, Value>这个类中的Key类型参数必须具有hash方法。
例如:
  1. interface Hashable {
  2.   hash(): number
  3. }
  4. class MyHashMap<Key extends Hashable, Value> {
  5.   public set(k: Key, v: Value) {
  6.     let h = k.hash();
  7.     // ...其他代码...
  8.   }
  9. }
复制代码
泛型函数(T)

使用泛型函数可编写更通用的代码。比如返回数组末了一个元素的函数:
  1. function last<T>(x: T[]): T {
  2.   return x[x.length - 1];
  3. }
  4. // 显式设置的类型实参
  5. last<string>(['aa', 'bb']);
  6. last<number>([1, 2, 3]);
  7. // 隐式设置的类型实参
  8. // 编译器根据调用参数的类型来确定类型实参
  9. last([1, 2, 3]);
复制代码
泛型默认值

泛型类型的类型参数可以设置默认值。这样可以不指定实际的类型实参,而只使用泛型类型名称。
空安全

默认情况下,ArkTS中的所有类型都是不可为空的,因此类型的值不能为空。这类似于TypeScript的严格空值查抄模式(strictNullChecks),但规则更严格。
  1. let x: number = null;    // 编译时错误
  2. let y: string = null;    // 编译时错误
  3. let z: number[] = null;  // 编译时错误
复制代码
可以为空值的变量定义为联合类型T | null。
  1. let x: number | null = null;
  2. x = 1;    // ok
  3. x = null; // ok
  4. if (x != null) { /* do something */ }
复制代码
非空断言运算符——后置!

后缀运算符!可用于断言其操作数为非空。
==应用于可空类型的值时,它的编译时类型变为非空类型。==例如,类型将从T | null更改为T:
  1. class A {
  2.   value: number = 0;
  3. }
  4. function foo(a: A | null) {
  5.   a.value;   // 编译时错误:无法访问可空值的属性
  6.   a!.value;  // 编译通过,如果运行时a的值非空,可以访问到a的属性;如果运行时a的值为空,则发生运行时异常
  7. }
复制代码
空值合并运算符——??

空值合并二元运算符??用于查抄左侧表达式的求值是否等于null或者undefined。如果是,则表达式的效果为右侧表达式;否则,效果为左侧表达式。
换句话说,a ?? b等价于三元运算符(a != null && a != undefined) ? a : b。
在以下示例中,getNick方法如果设置了昵称,则返回昵称;否则,返回空字符串:
  1. class Person {
  2.   // ...
  3.   nick: string | null = null
  4.   getNick(): string {
  5.     return this.nick ?? '';
  6.   }
  7. }
复制代码
可选链——后置?

在访问对象属性时,如果该属性是undefined或者null,可选链运算符会返回undefined。
可选链可以恣意长,可以包含恣意数量的?.运算符。
例子:在以下示例中,如果一个Person的实例有不为空的spouse属性,且spouse有不为空的nick属性,则输出spouse.nick。否则,输出undefined:
  1. class Person {
  2.   nick: string | null = null
  3.   spouse?: Person
  4.   constructor(nick: string) {
  5.     this.nick = nick;
  6.     this.spouse = undefined;
  7.   }
  8. }
  9. let p: Person = new Person('Alice');
  10. p.spouse?.nick; // undefined
复制代码
模块

程序可分别为多组编译单元或模块。
每个模块都有其自己的作用域,即,在模块中创建的任何声明(变量、函数、类等)在该模块之外都不可见,除非它们被显式导出。
与此相对,从另一个模块导出的变量、函数、类、接口等必须首先导入到模块中。
导出 ——关键字export

可以使用关键字export导出顶层的声明。?????????
未导出的声明名称被视为私著名称,只能在声明该名称的模块中使用。
注意:通过export方式导出,在导入时要加{}。
静态导入

导入声明用于导入从其他模块导出的实体,并在当前模块中提供其绑定。导入声明由两部分构成:
  1. 导入路径,用于指定导入的模块;
  2. 导入绑定,用于定义导入的模块中的可用实体集和使用形式(限定或不限定使用)。
复制代码
导入绑定可以有几种情势。
假设模块具有路径“./utils”和导出实体“X”和“Y”。
导入绑定* as A表现绑定名称“A”,通过A.name可访问从导入路径指定的模块导出的所有实体:
  1. import * as Utils from './utils'
  2. Utils.X // 表示来自Utils的X
  3. Utils.Y // 表示来自Utils的Y
复制代码
导入绑定{ ident1, …, identN }表现将导出的实体与指定名称绑定,该名称可以用作简单名称:
  1. import { X, Y } from './utils'
  2. X // 表示来自utils的X
  3. Y // 表示来自utils的Y
复制代码
如果标识符列表定义了ident as alias,则实体ident将绑定在名称alias下:
  1. import { X as Z, Y } from './utils'
  2. Z // 表示来自Utils的X
  3. Y // 表示来自Utils的Y
  4. X // 编译时错误:'X'不可见
复制代码
动态导入

应用开发的有些场景中,如果希望根据条件导入模块或者按需导入模块,可以使用动态导入代替静态导入。
import()语法通常称为动态导入,是一种类似函数的表达式,用来动态导入模块。以这种方式调用,将返回一个promise。
顶层语句

顶层语句是指在模块的最外层直接编写的语句,这些语句不被包裹在任何函数、类、块级作用域中。顶层语句包罗变量声明、函数声明、表达式等。
关键字

this

关键字this只能在类的实例方法中使用。
关键字this的指向:

  • 调用实例方法的对象
  • 正在构造的对象

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

农民

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表