hi 大家好,我是 DHL。大厂程序员,在美团、快手、小米工作过。公众号:ByteCode,分享有用的原创文章,涉及鸿蒙、Android、Java、Kotlin、性能优化、大厂面经

ArkTS 是 HarmonyOS 首选的开发语言,它在 TypeScript 的基础上做了一些优化和扩展,继承了 TypeScript 的优点,屏蔽了 TypeScript 的缺点,和 ArkUI 框架一起构建了鸿蒙应用,这篇文章我们主要介绍 ArkTS。

ArkTS 设计初衷旨在提高开发效率、代码质量和性能,所以需要满足以下场景。

  • 在实际工作中,代码阅读频率远远高于编写频率,因此 ArkTS 代码需非常容易阅读和理解
  • 以最小功耗快速执行代码

考虑到上面两点,因此在 ArkTS 中要求强制使用静态类型,这意味着在 ArkTS 中,你需要在声明变量、函数参数、函数返回值等时指定类型,并且在编译时会进行严格的类型检查。由于所有类型在程序运行前都是已知的,开发人员非常容易理解代码中使用了哪些数据结构,并且编译器可以提前验证代码的正确性,从而可以减少运行时的类型检查,有助于提升性能。

通过强制使用静态类型,ArkTS 提供了更强大的类型约束和类型推断功能,有助于在编译时捕获潜在的类型错误,提高代码的可靠性和可维护性。这种设计有助于开发者编写更加健壮和可靠的代码。

相比于 TypeScript 不使用静态类型可能会导致一些问题:

  • 难以捕获类型错误:如果不使用静态类型,很容易在代码中引入类型错误,这些错误可能只能在运行时被发现,降低了代码的可靠性。
  • 降低了开发效率:静态类型可以提供更好的代码补全、类型检查和重构支持。如果不使用静态类型,无法提供这些支持,降低了开发效率
  • 代码维护成本高:没有静态类型,代码的可读性和可维护性可能会下降

所以 ArkTS 在 TypeScript 的基础上,进一步完善了语言上的缺陷,无论是性能还是代码的可读性都非常的高,后面的文章我会单独分析 ArkTS 都屏蔽了 TypeScript 那些缺陷。

由于官网对于 ArkTS 的讲解太少了,而 ArkTS 是开发鸿蒙应用的关键,因此 ArkTS 我将拆分好几篇文章详细的分析 ArkTS 核心知识点。这篇文章主要介绍 ArkTS 的基础知识点。

我们先来看一下在 ArkTS 中用什么来声明一个变量。

let 和 const

在 ArkTs 中用关键字 let 和 const 声明变量。它们有些相同和不同之处,我们一起来分析一下。

let 和 const 不同之处

let 声明的变量是可变的,可以被再次赋值,而 const 声明的常量是不可变的,初始化完,值就不能被改变。

getData() {
    let name = "ByteCode";
    name = "DHL" // ok
    
    const age = 18;
    age = 20; // 这里会报错 Cannot assign to 'age' because it is a constant.
}

在上面的代码中,想尝试修改常量 age 的值,这个时候编译器会提示这是个常量不能被修改。

从结果来看被 const 修饰的变量的值不能被改变,但是实际上并不是变量的值不能被改变,而是变量指向的那个内存地址所保存的数据不能改变。

对于基本数据类型(数值、字符串、布尔值等等),变量指向的内存地址保存的是变量的值 ,因此初始化完不能被改变。

const number = 1;

在上面的代码中,number 指向的内存地址保存的是 number 初始化的值,因此 number 被声明之后不能被改变。

对于复杂数据类型(对象和数组)的变量指向的是内存地址,保存的是指向实际数据的指针,因此 const 只能保证内存地址保存的指针不能被改变,而它指向的实际数据是可以改变的。我们来看一段示例。

const language: string[] = ['ArkTs', 'Java', 'Kotlin'];
language[0] = "ByteCode"; // ok

const people: string[] = ['zhangsan', 'xiaohong', 'xiaoming'];
language = people; // 报错

我们可以通过索引修改数组 language,但是不能将 language 指向另外一个常量 people,否则就会报错。从这个例子我们可以知道 const 只能保证对象的指针不能被改变,但是对象里面的内容可以改变。

什么情况下使用 let 和 const

let 和 const 唯一的区别就是可变和不可变,let 可变,而 const 不可变。

因此在使用时,如果变量的值会发生变化,可以选择使用 let,而对于不会改变的常量值,应该选择 const,这样有助于提高代码的可读性和可维护性。

实际上我们在做业务需求的时候,大部分情况下都是接受数据(可能来自网络、本地、前一个页面),收到数据之后渲染 UI,所以这个时候数据是不会变的我们可以使用 const,但是如果我们要控制部分 UI 是否展示,这个情况可能需要使用 let。

let 和 const 相同之处

let 和 const 的作用域是相同,都是在声明所在的块级作用域内有效。

if (true) {
  let age = 18; // age 只在 if 语句内有效
}

if (true) {
  const name = "DHL"; // name 只在 if 语句内有效
}

try {
    //            
}catch (e) {
    变量 e 只能在 catch 范围内
}

无论是 let 还是 const 只能在它声明所在代码块内有效,只不过使用的场景有些不同,比如在 for 循环中,循环变量只能使用 let 声明。

for (let i = 0; i < 10; i++) {
  // ...
}

在上面的代码中,循环变量 i 只在 for 循环体内有效,在循环体外引用就会报错,但是需要注意了,在 ArkTS 中不能使用 for .. in,否则会有一个编译警告。

鸿蒙:5 分钟秒懂 ArkTs,不能错过的知识点解析_JavaScript

之所以不能使用 for .. in 是因为在 ArkTS 中,对象的布局在编译时是确定的,且不能在程序执行期间更改对象的布局,换句话说,ArkTS 禁止以下行为:

  • 向对象中添加新的属性或方法
  • 从对象中删除已有的属性或方法
  • 将任意类型的值赋值给对象属性

如果修改对象布局会影响代码的可读性以及运行时性能。从开发的角度来说,在某处定义类,然后又在其它地方修改了实际对象布局,这很容易引入错误,另外如果修改对象布局,需要在运行时支持,这样会增加执行开销降低性能。

for 循环还有一个特别的地方,我们来看看下面的代码,按照你多年的经验,你能在不执行代码的情况下,说出下面代码的运行结果吗。

for (let i = 0; i < 3; i++) {
  let i = 'abc';
  console.log(i);
}

以上代码是可以正常运行的,答案是输出了 3 个 abc,这就说明 for 循环内部声明的变量 i 和循环变量 i 不在同一个作用域,它们有各自单独的作用域。如果在同一个作用域,是不可使用 let 或者 const 重复声明相同名字的变量。比如下面的代码会报错。

if(true){
    let a = 1;
    let a = 2; // 报错
    
    const b = 3; 
    const b = 4; // 报错
}

基本数据类型

ArkTS 支持与 TypeScript 几乎相同的数据类型,如布尔型、数字、字符串、数组、枚举、Null 和 Undefined 等。

布尔值

let isDone: boolean = false;
const isDone: boolean = false;

数字

所有数字都是浮点数,这些浮点数的类型是 number

let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;
const binaryLiteral: number = 0b1010;
const octalLiteral: number = 0o744;

字符串

string 表示字符串类型,我们可以使用双引号(")或单引号(')声明一个字符串。

let name: string = "DHL";
const publicName: string = "ByteCode";

我们还可以使用模板字符串,这种字符串是被反引号包围,并且以 ${expr} 这种形式嵌入表达式。

let name = "DHL";
const content = `My name is ${name}`

数组

在 ArkTS 中有两种方式创建数组。

  • 元素类型后面接上 []
let list: number[] = [1, 2, 3];
  • 使用数组泛型 Array<元素类型>
let list: Array<number> = [1, 2, 3];

但是这里需要注意了,如果可以从传递给泛型函数的参数中推断出具体类型,ArkTS 允许省略泛型类型实参。否则,需要指定泛型类型实参,不然会报错。

枚举

enum 表示枚举类型。

export enum ResponseCode{
  SUCCESS =  1000,
  FAILED = 2000
}

Null 和 Undefined

NullUndefined 各自的类型分别为 nullundefined,例如可以将一个变量声明为 nullundefined

let u: undefined = undefined;
let n: null = null;
  • undefined :当声明了变量但未赋值时,该变量的值为 undefined,另外在访问对象属性或数组元素时,如果访问的属性或元素不存在,其值也为 undefined
  • null :通常用来表示变量被赋予了空值。它是一个空对象指针,用于显式地指示一个空值

感谢你的阅读,写技术文章不易,如果文章对你有帮助,欢迎在看、点赞、分享给身边的朋友,你的点赞是我持续更新的动力

我在 github 上新建了一个 HarmonyPractice 仓库,这个仓库主要用于演示 ArkTS 语法规则、鸿蒙组件的使用,以及鸿蒙实战项目。

最近新建了一个鸿蒙学习交流群,鸿蒙目前还处于初期发展阶段,网上对鸿蒙问题的解答太少了,而我在学习过程中也遇到了不少问题,花了不少时间去分析。有兴趣的小伙伴,可以看一下这篇文章,列举了我遇到的问题,以及解决方案。

  • 学习鸿蒙,解决这几个关键问题

相比于自己去摸索,通过与大家的沟通交流,效率会提高很多。所以我想建一个鸿蒙学习交流群,诚邀各位小伙伴一起来打造一个良好的学习氛围沟通群。欢迎私私信我。

2024,加油!

2024,一起见证彼此成长!

Hi 大家好,我是 DHL,在美团、快手、小米工作过。公众号:ByteCode ,分享有用的原创文章,涉及鸿蒙、Android、Java、Kotlin、性能优化、大厂面经,真诚推荐你关注我。



开源新项目

  • HarmonyPractice 仓库,这个仓库主要用于演示 ArkTS 语法规则、鸿蒙组件的使用,以及鸿蒙实战项目
  • 云同步编译工具(SyncKit),本地写代码,远程编译,欢迎前去查看 SyncKit
  • KtKit 小巧而实用,用 Kotlin 语言编写的工具库,欢迎前去查看 KtKit
  • 最全、最新的 AndroidX Jetpack 相关组件的实战项目以及相关组件原理分析文章,正在逐渐增加 Jetpack 新成员,仓库持续更新,欢迎前去查看 AndroidX-Jetpack-Practice
  • LeetCode / 剑指 offer,包含多种解题思路、时间复杂度、空间复杂度分析,在线阅读