4. ArkTS凭什么是鸿蒙开发首选?对比 JS/TS 详解语言特性

鸿蒙应用开发默认用 ArkTS 来写。它是在 TypeScript 上继续扩展出来的,骨架还是熟悉的那一套:变量、函数、类、模块,写起来和 TS 很接近。ArkTS 继承了 TypeScript 的大部分语法,已经会写 TS 的人不用大改手感。它盯着的是移动设备上的运行效率。很多语言设计的时候没把手机放在首位,应用到手机上容易又慢又费电。ArkTS 把运行时开销压下来,启动更快,功耗也更低。

动画视频在《4. ArkTS凭什么是鸿蒙开发首选?对比 JS/TS 详解语言特性》

ArkTS 把静态类型做成了强制要求。变量的类型是确定的,而且在程序真正运行之前就已经知道。编译器会在编译阶段核对代码,不少类型问题不用等应用装进手机才冒出来。类型提前定死,运行时就不必处处再查一遍「这到底是什么」,后面的优化也有了依据。另外还有两条配套限制:运行期间不能改对象的布局;一部分运算符被收窄,一元加号只能用在数字上。规矩比 TS 严,换来的是更少的运行时意外。

界面用组件描述出来。ArkTS 配的是 ArkUI 的声明式写法:用组件把页面搭好,再链式配上属性、事件,容器组件则在后面的花括号里放子组件。UI 就是应用状态的函数,状态一改,相应的界面就更新。状态管理会记下哪个组件读过哪个状态变量,变量变了,只把依赖它的组件标出来重绘。

ArkTS、JavaScript、TypeScript 三种源码,方舟编译器都能编成方舟字节码,后缀是 .abc。方舟字节码是 ArkTS、TS、JS 源码编译后的二进制产物,交给方舟运行时在设备上加载。工具链里干这件事的核心组件是 es2abc,输入可以是 js、ts,也可以是 ArkTS。字节码先由方舟运行时加载,到了设备上才会变成 CPU 能执行的指令。

JavaScript 走的是另一条路。它是动态类型,值在运行前不必固定成某一种类型,运算过程中还可能做隐式转换。类型对不对,常常要等代码真的执行到那一行才知道。引擎为了不出错,得在运行时确认对象是什么、属性能不能访问。这些检查里有一部分消不掉,运行前能做的优化就有限。ArkTS 把一元加号这类运算符收窄,也是在避开这种含混。

TypeScript 在 JavaScript 上加了类型标注,编译时能拦住一批错误。但它的类型不是强制的,漏标的代码仍然能写,检查就不完整。常规编译还会把标注擦掉,产出仍是 JavaScript,运行时回到动态类型。鸿蒙的工具链虽然也能把 TS 直接编成 abc,运行时对 TS 和 JS 仍保留动态对象的语义,该付的运行时开销还在。ArkTS 把静态类型收成语言规则,编出来的是字节码,检查和优化可以在跑起来之前做完。所以写鸿蒙应用,默认用 ArkTS。已有的 TS、JS 代码可以接进工程;一旦和动态对象打交道,那一部分就不再享受完整的静态检查。

工程落在 DevEco Studio 里。ArkTS 源码、图片和字体这些资源,还有 build-profile.json5 一类工程配置,都在这里写。点运行或者构建,DevEco Studio 会拉起 Hvigor。Hvigor 是任务编排工具,它按依赖把事情排开:处理依赖,编译资源,再编译 ArkTS。编译 ArkTS 时,前端会先把声明式组件语法转换成运行时能执行的形式,同时做语法检查和静态类型检查。es2abc 遇到语法错误会直接失败,错误停在 IDE 里,这一轮不会继续出安装包。

检查过了,方舟编译器才输出 .abc。后面是打包和签名。Hvigor 的任务顺序是先打 HAP,再给 HAP 签名。HAP 是能装到鸿蒙设备上的模块包。签名在工程里配好了,构建结果里会有已签名的包;没配的话,得到的是未签名包,还得再签一次才能装到真机。点运行时,编好的 HAP 会被部署到设备上;只做构建的话,产物在模块的 build 目录里。包进了设备,ArkTS 运行时加载 abc。运行时有三种执行方式:解释器、AOT、JIT。解释器直接执行字节码。AOT 是提前编译,可以在宿主机上把字节码编成目标设备的机器码,优化做足,设备上启动和运行更快。JIT 是跑起来之后再编译热点代码,这套动态编译器目前还在实验中。三条路的终点一样,指令最后都在设备 CPU 上执行。