
ArkTs基础
ArkTS是HarmonyOS应用开发的官方高级语言。语法类似于TypeScript,ArkTS提供了声明式UI范式、状态管理、渲染控制等相应的能力,让开发者能够以更简洁、更自然的方式开发应用。
ArkTS在TypeScript(简称TS)生态基础上做了进一步扩展,保持了TS的基本风格,同时通过规范定义强化开发期静态检查和分析,提升代码健壮性,并实现更好的程序执行稳定性和性能。对比标准TS的差异可以参考从TypeScript到ArkTS的适配规则。ArkTS同时也支持与TS/JavaScript(简称JS)高效互操作。
ArkTS基础类库和容器类库增强了语言的基础功能,提供包括高精度浮点运算、二进制Buffer、XML生成解析转换和多种容器库等能力,协助开发者简化开发工作,提升开发效率。
针对TS/JS并发能力支持有限的问题,ArkTS对并发编程API和能力进行了增强,提供了TaskPool和Worker两种并发API供开发者选择。另外,ArkTS进一步提出了Sendable的概念来支持对象在并发实例间的引用传递,提升ArkTS对象在并发实例间的通信性能。
方舟编译运行时(ArkCompiler)支持ArkTS、TS、JS的编译运行,目前它主要分为ArkTS编译工具链和ArkTS运行时两部分。其中ArkTS编译工具链负责在开发侧将高级语言编译为方舟字节码文件(*.abc),而ArkTS运行时则负责在设备侧运行字节码文件执行程序逻辑。
基础语法
Hello World
console.log('我说', 'Hello World')
数据类型和变量,常量定义
变量常量的注意事项(命名规则):
① 只能包含数字、字母、下划线、$,不能以数字开头
② 不能使用内置关键字或保留字 (比如 let、const)
③ 严格区分大小写
三种常见的基础数据类型:
① string 字符串:描述信息
② number 数字:计算
③ boolean 布尔:判断 (真、假)
变量:专门用来存储数据的容器 (可变)
let 变量名: 类型 = 值
let title: string = '奥利奥'
let price: number = 3.14
let isSelect: boolean = true
title = '燕麦'
常量:用来存储数据 (不可变)
const 常量名: 类型 = 值
const PI: number = 3.1415926
数组
数组:是一个容器,可以存储多个数据
let 数组名: 类型[] = [数据1, 数据2,...]
let names: string[] = ['小红', '小明', '大强']
注意:数组指定的类型和存储的数据类型要必须一致,否则会报错
获得数组元素: 数组名[索引]
let names: string[] = ['小红', '小明', '大强']
console.log('取出小明', names[1])
注意:索引号是从 0 开始的
对象数组
// 1. 定义接口
interface Person {
stuId: number
name: string
gender: string
age: number
}
// 2. 基于接口构建对象数组
let pArr: Person[] = [
{ stuId: 1, name: '小丽', gender: '女', age: 12 },
{ stuId: 2, name: '小王', gender: '男', age: 11 },
{ stuId: 3, name: '大强', gender: '男', age: 13 },
{ stuId: 4, name: '小张', gender: '男', age: 11 },
{ stuId: 5, name: '小美', gender: '女', age: 12 },
]
通过下标即可访问,通过 for of 可以遍历
数组的操作
查找 & 修改
查找: 数组名[下标]
修改: 数组名[下标] = 新值
数组长度:数组名.length
let names: string[] = ['小明', '小红', '大强', '小飞']
// 1. 查找
console.log('查找姓名', names[0])
// 2. 长度
console.log('数组长度为', names.length)
// 3. 修改
names[1] = 'Jack'
console.log('names数组', names)
增加数组元素
往开头加: 数组名.unshift(数据1, 数据2, 数据3, ......)
结尾添加:数组名.push(数据1, 数据2, 数据3, ......)
let songs: string[] = ['告白气球', '洋葱', '吻别']
// unshift():开头新增 (返回操作后数组的长度)
songs.unshift('你是我的眼')
// push():结尾新增 (返回操作后数组的长度)
songs.push('光辉岁月', '海阔天空')
console.log('数组songs', songs)
删除数组元素
从开头删: 数组名.shift()
从结尾删: 数组名.pop()
let songs: string[] = ['告白气球', '洋葱', '吻别']
// shift(): 开头删除 (返回值: 删除的项)
songs.shift()
// pop(): 结尾删除 (返回值: 删除的项)
songs.pop()
console.log('数组songs', songs)
任意位置添加 / 删除数组元素
语法:数组名.splice(起始位置, 删除的个数, 新增元素1, 新增元素2, ......)
let songs: string[] = ['告白气球', '洋葱', '吻别']
// 删除下标为2的元素 ['告白气球', '洋葱']
songs.splice(2, 1)
console.log('数组songs', songs)
函数-Function
函数:是可以被重复使用的代码块
1. 定义函数
function 函数名() {
函数体
}
2. 调用函数
函数名()
函数的完整用法
function 函数名(需要处理的数据//形参) {
编写代码对数据进行处理
return 处理后的结果
}
let 变量名: 类型 = 函数名(实际要处理的数据//实参)
根据我们传入不同的数据,进行处理,返回处理后的结果。
function 函数名(形参1:类型, 形参2:类型 ...) {
编写代码对数据进行处理
return 处理后的结果
}
let 变量名: 类型 = 函数名(实参1, 实参2, ..)
箭头函数
箭头函数是 比普通函数 更简洁 的一种函数写法
let 函数名 = () => {
// 函数体
}
函数名()
let 函数名 = (形参1: 类型, 形参2: 类型) => {
// 函数体
}
函数名(实参1, 实参2)
let 函数名 = (形参1: 类型, 形参2: 类型) => {
// 函数体
// 1. 计算过程
// 2. 返回结果
return 计算的结果
}
函数名(实参1, 实参2)
示例:
let buy = (price: number, weight: number) => {
let result: number = price * weight
return result
}
let apple: number = buy(2, 3)
对象
作用:用于描述一个物体的特征和行为。
对象:是一个可以存储多个数据的容器。
对象-定义和使用
let 对象名称: 对象结构类型 = 值
1. 通过 interface 接口约定 对象结构类型
interface 接口名 {
属性1: 类型1
属性2: 类型2
属性3: 类型3
}
interface Person {
name: string
age: number
weight: number
}
2. 定义对象并使用(通过 . 访问)
let person: Person = {
name: '小明',
age: 18,
weight: 120
}
console.log('名字', person.name)
console.log('年纪', person.age)
console.log('体重', person.weight)
对象 – 方法
方法作用:描述对象的具体行为
1. 约定方法类型
interface 接口名称 {
方法名: (参数:类型) => 返回值类型
}
interface Person{
run: () => void
sing: (song: string) => void
}
2. 添加方法(箭头函数)
对象名.方法名(实参)
let xm: Person = {
run: () => {
console.log('小明说', '我在跑步')
},
sing: (song: string) => {
console.log('小明说', '我来唱首', song)
}
}
ym.dance()
ym.sing('七月上')
联合类型
联合类型是一种灵活的数据类型,它修饰的变量可以存储不同类型的数据。
let 变量: 类型1 | 类型2 | 类型3 = 值
let judge: number | string = 100
judge = 'A'
把变量值限定在一组数据范围内选择
let gender: 'man' | 'woman' | 'secret'
基于联合类型,变量可存不同类型数据
枚举类型
枚举类型是一种特殊的数据类型,约定变量只能在一组数据范围内选择值。
1. 定义枚举类型(常量列表)
enum 枚举名 {
常量1 = 值,
常量2 = 值,
......
}
enum ThemeColor {
Red = '#ff0f29',
Orange = '#ff7100',
Green = '#30b30e'
}
2. 使用枚举类型,约束变量
let color: ThemeColor = ThemeColor.Red
console.log('主页颜色', color)
取值从枚举中(常量列表中)取
字符串拼接
作用:把两个或多个字符串,拼成一个字符串。(通常拼接的是字符串和变量)
加号的作用:拼接
'hello' + 'world' => 'helloworld'
let name: string = '小明'
console.log('简介信息', '名字是' + name)
注意: 加法两端只要有字符串,就是拼接
模板字符串
例如`hello`
作用:拼接字符串和变量
优势:更适合于 多个变量 的字符串拼接
适合复杂场景
let name: string = '小明'
let age: number = 18
console.log('简介信息', `姓名是${name},今年${age}岁了`)
适合简易场景
let name: string = '小明'
let age: number = 18
console.log('简介信息', '姓名是' + name + ',今年' + age + '岁了')
类型转换
1. 字符串转数字
Number():字符串 直接转数字,转换失败返回NaN(字符串中包含非数字)
let str1:string ='1.1'
let str2: string ='1.9'
let str3:string ='1.1a
console.log('数字是',Number(str1))// 1.1
console.log('数字是',Number(str2))// 1.9
console.log('数字是',Number(str3))// NaN
parseInt():去掉小数部分 转数字,转换失败返回NaN
let strl: string= '1.1'
let str2: string='1.9'
let str3:string ='1.1a'
let str4:string ='a'
console.log('数字是',parseInt(str1))// 1
console.log('数字是',parseInt(str2))// 1
console.log('数字是',parseInt(str3))// 1
console.log('数字是',parseInt(str4))// NaN
parseFloat():保留小数部分 转数字,转换失败返回NaN
let strl:string='1.1'
let str2:string ='1.9'
let str3:string ='1.1a
let str4:string ='a'
console.log('数字是',parseFloat(str1))// 1.1
console.log('数字是',parseFloat(str2))// 1.9
console.log('数字是',parseFloat(str3))//1.1
console.log('数字是',parseInt(str4)) // NaN
2.数字转字符串
toString():数字直接转字符串
let numl:number=1.1
let num2:number=1.9
console.log('字符串是',num1.tostring())//'1.1'
console.log('字符串是',num2.toString())//'1.9'
toFixed():四舍五入转字符串,可设置保留几位小数
let numl:number= 1.1
let num2:number = 1.9
let num3:number=1.9152
console.log('字符串是',num1.toFixed()) //'1'
console.log('字符串是',num2.toFixed()) //'2'
console.log('字符串是',num3.toFixed(2)) //'1.92'
运算符
算术运算符
算术运算符:也叫数学运算符,主要包括加、减、乘、除、取余(求模)等
let num1:number = 9
let num2:number = 4
console.log('加法计算',num1 + num2)
console.log('减法计算',num1 - num2)
console.log('乘法计算',num1 * num2)
console.log('除法计算',num1 / num2)// 2.25
console.log('取余计算',num1 % num2)// 1
赋值运算符
赋值运算符:对变量进行赋值的运算符,如:=
+=加法赋值,-=减法赋值,*=乘法赋值,/=除法赋值,%=取余赋值
let num1:number=1
num1 += 1
console.log('加等后的结果',num1)
一元运算符
常见一元运算符:++和--
后置写法:先赋值后自增/自减
前置写法:先自增/自减再赋值
let num: number = 10
let res: number = num++//后自增
let num2: number = 10
let res2: number = ++num//先自增
比较运算符
作用:用来判断比较两个数据大小,返回一个布尔值(true / false)
let num1: number = 9
let num2: number = 5
console.log('比较运算的结果是', num1 > num2)
console.log('比较运算的结果是', num1 >= num2)
console.log('比较运算的结果是', num1 == num2)
console.log('比较运算的结果是', num1 != num2)
逻辑运算符
作用:扩充判断条件
&&与,都真才真,||或,一真则真,!非,取反
运算符优先级
优先级
1小括号( )
2一元++、--、!
3算数先*、/、% 后+、-
4比较>、>=、<、<=
5比较==、!=
6逻辑运算符先&& 后||
7赋值=
语句
语句概念
语句: 一段可以执行的代码,是一个行为 ( num = a + b )
表达式: 可以 被求值 的代码,并将其计算出 一个结果 (1 + 1、3 * 5、3 > 2)
语句执行结构:
分支语句
if 分支语句
if 分支语句:根据 逻辑条件 不同,执行不同语句。
小括号条件结果为 true,则执行大括号里面的代码
小括号结果不是布尔类型时,会类型转换为布尔值
if (逻辑条件) {
条件成立执行的代码
}
根据 逻辑条件 不同,执行不同语句。
if (逻辑条件) {
条件成立执行的代码
}
else {
条件不成立执行的代码
}
if 多分支
if (条件1) {
条件1成立执行的代码
}
else if (条件2) {
条件2成立执行的代码
}
else if (条件3) {
条件3成立执行的代码
}
else {
都不成立执行的代码
}
switch 分支
switch 分支一般用于精确匹配,不同的值执行不同的代码
switch (表达式) {
case 值1:
与值1匹配执行的语句
break
case 值2:
与值2匹配执行的语句
break
default:
以上都未成功匹配执行的代码
}
注意:如果没有break语句,则会直接执行 switch 中的下一个代码块(无论是否匹配成功)
三元条件表达式
语法:条件 ?条件成立执行的表达式 :条件不成立执行的表达式
let num1: number = 5
let num2: number = 10
// 返回较大值
let res: number = num1 > num2 ? num1 : num2
console.log('結果是', res)
循环语句
Tips:循环三要素
1. 初始值(变量)
2. 循环条件
3. 变化量(变量计数,自增或自减)
while 语句
作用:重复执行指定的一段代码
while (条件) {
条件成立重复执行的代码
}
/*
while (true) {
console.log('while', '重复执行的代码')
}
*/
// 指定循环次数
let i: number = 1
while (i < 5) {
console.log('while~i', '重复执行的代码')
i++
}
for 语句
作用:重复执行指定的一段代码
while (条件) {
条件成立重复执行的代码
}
/*
while (true) {
console.log('while', '重复执行的代码')
}
*/
// 指定循环次数
let i: number = 1
while (i < 5) {
console.log('while~i', '重复执行的代码')
i++
}
退出循环
作用:满足指定条件,可以退出循环
break:终止整个循环
continue: 退出当前一次循环的执行,继续执行下一次循环
遍历数组
遍历:将数组里面的每个数据,按顺序访问一遍
let names: string[] = ['小红', '小明', '大强']
for(let i = 0; i < names.length; i++) {
console.log('名字是', names[i])
}
遍历数组 – for ... of
语法: for (let item of 数组名) {}
for ... of : 在 ... 之中 进行循环
item: 声明的一个变量, 用来在循环的时候接收 每一个数组元素
let names: string[] = ['小红', '小明', '大强']
for(let i = 0; i < names.length; i++) {
console.log('名字是', names[i])
}
for (let item of names) {
console.log('for...of...名字是', item)
}
class 类
类是用于 创建对象 模板。同时类声明也会引入一个 新类型,可定义其 实例属性、方法 和 构造函数。
// 类名 首字母大写(规范)
class 类名{
// 1. 实例属性(字段)
// 2. 构造函数
// 3. 方法
}
// 使用类 实例化对象 基于类 创建对象
const p:类名 = new 类名()
1. Class类 实例属性
通过实例属性(字段),可以保存各种类型的数据
// 类
class 类名{
// 字段名、类型、初始值
字段名1:类型='xxx'
// 可选字段可以不设置初始值
字段名2?:类型
}
// 可选字段在使用时需要配合 可选链操作符 避免出错
const p: 类名 = new 类名()
p.字段名1
p?.字段名2
class Person {
name: string = 'jack'
food?: string
}
const p = new Person()
p.name = 'tom'
console.log(p.name)
console.log('字符串', p.food?.length)
2. Class类 构造函数
不同实例,将来需要有不同的字段初始值,就需要通过构造函数实现
class 类{
字段A:类型
字段B:类型
constructor(参数...) {
// 通过 new 实例化的时候 会调用 constructor
// 通过关键字 this 可以获取到实例对象
this.字段名A = 参数
}
}
const 实例1 = new 类(参数...)
const 实例2 = new 类(参数...)
class Food {
name: string
price: number
constructor(name:string, price:number) {
this.name = name
this.price = price
}
}
const f1 = new Food('西红柿鸡蛋', 15)
const f2 = new Food('土豆炖鸡块', 24)
3. Class类 定义方法
类中可以定义方法,并且在内部编写逻辑
class 类名{
方法名(参数...):返回值类型{
// 逻辑...
// 可以通过 this 获取实例对象
}
}
class Person{
name:string
constructor(name:string) {
this.name = name
}
sayHi(name:string){
console.log(`你好${name}, 我是:${this.name}`)
}
}
const p:Person = new Person('jack')
p.sayHi('rose')
4. 静态属性 和 静态方法
类还可以添加 静态属性、方法,后续访问需要通过 类 来完成
// 定义
class 类{
static 字段:类型
static 方法(){}
}
// 使用
类.字段
类.方法()
// 静态属性和方法
class Robot {
// 如果不设置值, 默认是 undefined
static version: string = '10.12'
// 工具方法
static getRandomNumber () {
return Math.random()
}
}
Robot.version
Robot.getRandomNumber()
5. 继承 extends 和 super 关键字
类可以通过 继承 快速获取另外一个类的 字段 和 方法
子类通过 super 可以访问父类的实例字段、实例方法和构造函数。
class 父类 {
// 字段
// 方法
// 构造函数
}
class 子类 extends 父类{
// 自己的字段(属性)
// 自己的方法
// 可以重写父类方法
}
class 父类 {
func(){
}
}
class 子类 extends 父类 {
constructor() {
super() // 调用父类构造函数
}
方法(){
super.方法() // 调用父类方法
}
}
6. instanceof 检测是否实例
instanceof 运算符可以用来检测某个对象是否是某个类的实例
实例对象 instanceof Class
typeof 表达式
7. 修饰符(readonly、private ...)
类的 方法 和 属性 可以通过修饰符来 限制 访问
修饰符包括:readonly、private、protected 和 public。省略不写默认为 public
readonly
class 类{
readonly 属性:类型
}
只可以取值,无法修改
private
private 修饰的成员不能在声明该成员的类之外访问, 包括子类
class 类{
private 属性:类型
private 方法(){}
}
class Person {
private name: string = ''
private age: number = 0
sayHi() {
// 内部可以访问
console.log(`你好,我叫:${this.name}`)
}
}
class Student extends Person{
sayHello() {
// 无法访问 报错
console.log(`你好,我叫:${super.name}`)
}
}
const p = new Person()
// p.name // 无法访问 报错
p.sayHi()
protected
protected修饰符的作用与private修饰符非常相似
不同点是protected修饰的成员允许在 派生类(子类) 中访问
class 类{
protected 属性:类型
protected 方法(){}
}
class Person {
protected name: string = ''
protected age: number = 0
sayHi() {
// 内部可以访问
console.log(`你好,我叫:${this.name}`)
}
}
class Student extends Person{
sayHello() {
// 可以访问到父类的protected属性
console.log(`你好,我叫:${super.name}`)
}
}
const p = new Person()
// p.name // 无法访问 报错
p.sayHi()
public
public 修饰的类成员(字段、方法、构造函数)
在程序的任何可访问该类的地方都是可见的 (默认)
class 类{
public 属性:类型
public 方法(){}
}
class Person {
public name: string = ''
public age: number = 0
sayHi() {
// 内部可以访问
console.log(`你好,我叫:${this.name}`)
}
}
class Student extends Person{
sayHello() {
// 可以访问到父类的protected属性
console.log(`你好,我叫:${super.name}`)
}
}
const p = new Person()
// p.name // 可以访问
p.sayHi()
readonly只读,无限制
private私有类,内部可以访问
protected保护,类及子类可以访问
public公共,无限制
剩余参数 和 展开运算符
剩余参数的语法,我们可以将 函数 或 方法 中一个不定数量的参数表示为一个数组
// 剩余参数只能写在最后一位
function 函数名(参数1,参数2,...剩余参数数组){
// 逻辑代码
// 之前的参数:挨个获取即可
// 剩余参数:以数组的形式获取
}
functionsum(numA:number,numB:number,...theArgs:number[]) {
let total = numA+numbB;
for (const arg of theArgs) {
total += arg;
}
return total;
}
console.log(sum(1, 2, 3).toString()) // 6
console.log(sum(1, 2, 3, 4).toString()) // 10
出于程序稳定性,以及运行性能考虑,在 ArkTS 中 ...(展开运算符) 只能用在数组上
const numArr1: number[] = [1, 2, 3, 4]
const numArr2: number[] = [5, 6, 7]
// 合并到一起
const totalArr: number[] = [...numArr1,...numArr2]
接口补充
接口继承使用的关键字是 extends
interface 接口1{
属性1:类型
}
interface 接口2 extends 接口1 {
属性2:类型
}
interface IAnimal {
name: string
}
interface ICat extends IAnimal {
color: string
}
const cat: ICat = {
name: '加菲猫',
color: '黑色'
}
可以通过接口结合 implements 来限制 类 必须要有 某些属性 和 方法
interface 接口{
属性:类型
方法:方法类型
}
class 类 implements 接口{
// 必须实现 接口中定义的 属性、方法,
// 否则会报错
}
interface IDog {
name: string
bark: () => void
}
class Dog implements IDog {
name: string = ''
food: string = ''
bark() {
}
}
泛型
泛型函数
泛型可以让【函数】等, 与多种【不同的类型】一起工作,灵活可复用
通俗一点就是:类型是 可变 的!
function 函数名<Type>(temp:Type):Type{
return temp
}
fn<string>('123')
fn<number>(1)
泛型约束
之前的类型参数,可以传递任何类型,没有限制。
如果希望有限制 → 泛型约束
interface 接口{
属性:类型
}
function 函数<Type extends 接口>(){}
// 传入的类型必须要有 接口中的属性
interface ILength {
length: number
}
function fn<T extends ILength>(param: T) {
console.log('', param.length)
}
多个泛型参数
日常开发的时候,如果有需要,可以添加多个 类型变量
function funcA<T, T2>(param1: T, param2: T2) {
console.log('参数 1', param1)
console.log('参数 2', param2)
}
funcA<string, number>('大白菜', 998)
funcA<string[], boolean[]>(['小老虎'], [false])
泛型接口
定义接口的时候,结合泛型定义,就是泛型接口
interface 接口<Type>{
// 内部使用Type
}
interface IdFunc<Type> {
id: (value: Type) => Type
ids: () => Type[]
}
let obj: IdFunc<number> = {
id(value) { return value },
ids() { return [1, 3, 5] }
}
泛型类
定义类的时候,结合泛型定义,就是泛型类。
class 类名<Type>{
// 内部可以使用 Type
}
// 定义
class Person <T> {
id: T
constructor(id: T) {
this.id = id
}
getId(): T {
return this.id
}
}
// 使用
let p = new Person<number>(10)