ArkTS基础合集!

292 阅读11分钟

[TOC]

(ArkTS的基本语法已经更新完毕,接下来将更新ArkTS进阶语法,敬请期待.....)

ArkTS 语言

1.初识ArkTS 语言🚶‍♀️

1.ArKTS是什么

ArKTs是Harmony OS优选的主力应用开发语言。ArkTS围绕应用开发在TypeScript(简称TS)生态基础上做了进一步扩展,保持了TS的基本风格,同时通过规范定义强化开发期静态检查和分析,提升程序执行稳定性和性能。

(就是在TS的基础上增加了一些新的特性)

2.ArkTS的编程规范🚶‍♀️🚶‍♂️

​ 1.类采用首字母大写的驼峰命名法,类名通常是名词或名词短语,例如Person、Student、Worker。

// 类名
class User {
  username: string

  constructor(username: string) {
    this.username = username;
  }

  sayHi() {
    console.log('hi' + this.username);
  }
}

// 枚举名
enum UserType {
  TEACHER = 0,
  STUDENT = 1
};

​ 2.函数的命名通常是动词或动词短语,采用小驼峰命名

let msg = 'Hello world';

function sendMsg(msg: string) {
  // todo send message
}

let userName = 'Zhangsan';

function findUser(userName: string) {
  // todo find user by user name
}

​ 3.常量名、枚举值名采用全部大写,单词间使用下划线隔开

const MAX_USER_SIZE = 10000;

enum UserType {
  TEACHER = 0,
  STUDENT = 1
};

4.避免使用否定的布尔变量名

//错误命名
let isNoError = true;
let isNotFound = false;

function empty() {}
function next() {}
//正确命名
let isError = false;
let isFound = true;

function isEmpty() {}
function hasNext() {}

5.使用空格缩进,禁止使用tab字符

6.多个变量定义和赋值语句不允许写在一行

//反例
let maxCount = 10, isCompleted = false;
let pointX, pointY;
pointX = 10; pointY = 0;
//正确写法
let maxCount = 10;
let isCompleted = false;
let pointX = 0;
let pointY = 0;

7.数组遍历优先使用Array对象方法***

对于数组的遍历处理,应该优先使用Array对象方法,如:forEach(), map(), every(), filter(), find(), findIndex(), reduce(), some()。

//反例
const numbers = [1, 2, 3, 4, 5];
// 依赖已有数组来创建新的数组时,通过for遍历,生成一个新数组
const increasedByOne: number[] = [];
for (let i = 0; i < numbers.length; i++) {
  increasedByOne.push(numbers[i] + 1);
}
//正确写法
const numbers = [1, 2, 3, 4, 5];
// better: 使用map方法是更好的方式
const increasedByOne: number[] = numbers.map(num => num + 1);

8.不要在控制性条件表达式中执行赋值操作

控制性条件表达式常用于if、while、for、?:等条件判断中。

在控制性条件表达式中执行赋值,常常导致意料之外的行为,且代码的可读性非常差。

//反例
// 在控制性判断中赋值不易理解
if (isFoo = false) {
  ...
}
//正确写法
const isFoo = someBoolean; // 在上面赋值,if条件判断中直接使用
if (isFoo) {
  ...
}

9.使用T[]表示数组类型

ArkTS提供了两种数组类型的表示方式:T[]和Array。为了代码的可读性,建议所有数组类型均用T[]来表示。

//反例
let x: Array<number> = [1, 2, 3];
let y: Array<string> = ['a', 'b', 'c'];
// 统一使用T[]语法
let x: number[] = [1, 2, 3];
let y: string[] = ['a', 'b', 'c'];

.......

3.从Ts到ArkTS的注意点

背景:

动态类型语言,例如JavaScript(简称JS),可以使得开发者非常快速地编写代码,但是同时,它也使得程序容易在运行时产生非预期的错误。例如在代码中,如果开发者没有检查一个值是否为undefined,那么程序有可能在运行时崩溃,给开发者造成不便。如果能在代码开发阶段检查此类问题是更有好处的。TS通过标注类型帮助开发者检查错误,许多错误在编译时可以被编译器检测出来,不用等到程序运行时。但是,即使是TS也有局限性,它不强制要求对变量进行类型标注,导致很多编译时检查无法开展。ArkTS尝试克服这些缺点,它强制使用静态类型,旨在通过更严格的类型检查以减少运行时错误

1.显式初始化类的属性

//非严格模式下的TS代码。
class Person {
  name: string // 可能为undefined
  
  setName(n: string): void {
    this.name = n
  }
  
  getName(): string {
  // 开发者使用"string"作为返回类型,这隐藏了name可能为"undefined"的事实。
  // 更合适的做法是将返回类型标注为"string | undefined",以告诉开发者这个API所有可能的返回值的类型。
    return this.name
  }
}

let buddy = new Person()
// 假设代码中没有对name的赋值,例如没有调用"buddy.setName('John')"
buddy.getName().length; // 运行时异常:name is undefined

//由于ArkTS要求属性显式初始化,代码应该像下面这样写。
class Person {
  name: string = ''//显式声明
  
  setName(n: string): void {
    this.name = n
  }
  
  // 类型为"string",不可能为"null"或者"undefined"
  getName(): string {
    return this.name
  }
}

let buddy = new Person()
// 假设代码中没有对name的赋值,例如没有调用"buddy.setName('John')"
buddy.getName().length; // 0, 没有运行时异常

。。。。

2.ArkTS的基本语法🏃‍♀️

1.声明

ArkTS中的console.log()第一个参数只能打印string类型与js有所不同需要注意一下
static log(message: string, ...arguments: any[]): void;

1.变量声明

let hi: string = 'hello';
hi = 'hello, world';

2.常量声明

const hello: string = 'hello';

3.自动类型推断

let hi1: string = 'hello';
let hi2 = 'hello, world';

2.类型

1.Number类型

2.Boolean类型

3.String类型

4.Void类型

5.Object类型 (Object类型是所有引用类型的基类型。任何值,包括基本类型的值(它们会被自动装箱),都可以直接被赋给Object类型的变量 )

let x:object = new  Number(1)

6.Array类型

7.Enum类型

enum ColorSet { Red, Green, Blue }
let c: ColorSet = ColorSet.Red;
console.log('枚举',JSON.stringify(c) )
// 枚举 {"0":"Red","1":"Green","2":"Blue","Red":0,"Green":1,"Blue":2}
enum ColorSet { White = 0xFF, Grey = 0x7F, Black = 0x00 }
let c: ColorSet = ColorSet.Black;
console.log('枚举',c)
// 枚举 0(16进制)

8.Union类型

class Cat {
  name: string = 'cat';
  // ...
}
class Dog {
  name: string = 'dog';
  // ...
}
class Frog {
  name: string = 'frog';
  // ...
}
type Animal = Cat | Dog | Frog | number;
// Cat、Dog、Frog是一些类型(类或接口)

let animal: Animal = new Cat();
animal = new Frog();
animal = 42;
// 可以将类型为联合类型的变量赋值为任何组成类型的有效值

9.type类型别名

含义:类型别名,顾名思义就是给某个类型起别名,之后就可以通过这个别名来使用类型啦。咱们开发中用到的一些内置类型就是通过 type 来定义的哦

// 定义类型别名
type IDType = string | number

// 使用类型别名
function printID(id:IDType ) {
  console.log(id+'')
}

// 调用函数
printID(10)
printID('20')

@Entry
@Component
struct Page01_type {
  @State message: string = 'Type类型别名';

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(30)
          .fontWeight(FontWeight.Bold)
      }
      .width('100%')
    }
    .height('100%')
  }
}

10.typeof运算符

​ 可以通过 typeof 运算符来获取类型,他返回的是一个字符串

// 前面 5 个可以正常获取到类型
console.log(typeof 123) // number
console.log(typeof '123') // string
console.log(typeof false) // boolean
console.log(typeof undefined) // undefined

function func() {
}

console.log(typeof func) // function

interface Person{
  name:string
}

// 对象 数组 null 获取到的都是 object
const p: Person = {name:'jack'}
console.log(typeof null) // object
console.log(typeof [1, 2, 3]) // object
console.log(typeof p) // object

3.运算符

(和前端开发的运算符基本一样☺)

1.赋值运算符

赋值运算符=,使用方式如x=y。

复合赋值运算符将赋值与运算符组合在一起,其中x op = y等于x = x op y。

复合赋值运算符列举如下:+=、-=、*=、/=、%=、<<=、>>=、>>>=、&=、|=、^=。

2.比较运算符

运算符说明
===如果两个操作数严格相等(对于不同类型的操作数认为是不相等的),则返回true。
!==如果两个操作数严格不相等(对于不同类型的操作数认为是不相等的),则返回true。
==如果两个操作数相等,则返回true。
!=如果两个操作数不相等,则返回true。
如果左操作数大于右操作数,则返回true。
>=如果左操作数大于或等于右操作数,则返回true。
<如果左操作数小于右操作数,则返回true。
<=如果左操作数小于或等于右操作数,则返回true。

3.算术运算符

一元运算符为-、+、--、++。

二元运算符列举如下:

运算符说明
+加法
-减法
*乘法
/除法
%除法后余数

4.位运算符

运算符说明
a & b按位与:如果两个操作数的对应位都为1,则将这个位设置为1,否则设置为0。
a | b按位或:如果两个操作数的相应位中至少有一个为1,则将这个位设置为1,否则设置为0。
a ^ b按位异或:如果两个操作数的对应位不同,则将这个位设置为1,否则设置为0。
~ a按位非:反转操作数的位。
a << b左移:将a的二进制表示向左移b位。
a >> b算术右移:将a的二进制表示向右移b位,带符号扩展。
a >>> b逻辑右移:将a的二进制表示向右移b位,左边补0。

5.逻辑运算符

运算符说明
a && b逻辑与
a || b逻辑或
! a逻辑非

4.语句

1.if语句

2.Switch语句

switch (expression) {
  case label1: // 如果label1匹配,则执行
    // ...
    // 语句1
    // ...
    break; // 可省略
  case label2:
  case label3: // 如果label2或label3匹配,则执行
    // ...
    // 语句23
    // ...
    break; // 可省略
  default:
    // 默认语句
}

3.条件表达式

condition ? expression1 : expression2
如果condition的为真值(转换后为true的值),则使用expression1作为该表达式的结果;否则,使用expression2。

4.For语句

5.For-of语句

使用for-of语句可遍历数组或字符串。示例如下:
for (let ch of 'a string object') {
  /* process ch */
}

6.While语句

7.Do-while语句

如果condition的值为真值(转换后为true的值),那么statements语句会重复执行。示例如下:
do {
  statements
} while (condition)

8.Break语句 :使用break语句可以终止循环语句或switch。

9.Continue语句 :continue语句会停止当前循环迭代的执行,并将控制传递给下一个迭代。

10.Throw和Try语句

---------------------------------------------------第一次更新完毕-----------------------------------------

5.函数

1.函数声明

//函数声明引入一个函数,包含其名称、参数列表、返回类型和函数体。
function add(x: string, y: string): string {
  let z: string = `${x} ${y}`;
  return z;
}

2.可选参数

//?表示参数可以有也可以没有
function hello(name?: string) {
  if (name == undefined) {
    console.log('Hello!');
  } else {
    console.log(`Hello, ${name}!`);
  }
}

//设置默认值
function multiply(n: number, coeff: number = 2): number {
  return n * coeff;
}
multiply(2);  // 返回2*2
multiply(2, 3); // 返回2*3

3.Rest参数

function sum(...numbers: number[]): number {
  let res = 0;
  for (let n of numbers)
    res += n;
  return res;
}

sum(); // 返回0
sum(1, 2, 3); // 返回6

展开运算符

​ 出于程序稳定性,以及运行性能考虑,在 ArkTS 中 ...(展开运算符) 只能用在数组上

​ (注:TS中 ... 数组和对象均可以使用 )

const numArr1: number[] = [1, 2, 3, 4]
const numArr2: number[] = [5, 6, 7]

// 合并到一起
const totalArr: number[] = [...numArr1, ...numArr2]

// 添加
const numArr3:number[] = [8,9,10]
const numArr4:number[] = [11,12,13]

// 将 numArr4 展开,传递给push
numArr3.push(...numArr4)

4.返回值

// 显式指定返回类型
function foo(): string { return 'foo'; }

// 推断返回类型为string
function goo() { return 'goo'; }

5.函数作用域

函数中定义的变量和其他实例仅可以在函数内部访问,不能从外部访问。

如果函数中定义的变量与外部作用域中已有实例同名,则函数内的局部变量定义将覆盖外部定义。

6.函数调用

function join(x: string, y: string): string {
  let z: string = `${x} ${y}`;
  return z;
}
let x = join('hello', 'world');
console.log(x); //hello world

7.声明函数类型(一般用于定义回调函数)

// 这是一个函数类型
type trigFunc = (x: number) => number

function do_action(f: trigFunc) {
  //在ArkTS中函数的参数一定要限制
  console.log('绝对值为',f(-1))
}
do_action(Math.abs); // 将函数作为参数传入

8.箭头函数(又名Lambda函数)

1.函数可以定义为箭头函数(要记得用变量接收)

let sum = (x: number, y: number): number => {
  return x + y;
}

2.箭头函数的返回类型可以省略;省略时,返回类型通过函数体推断。
3.表达式可以指定为箭头函数,使表达更简短,因此以下两种表达方式是等价的:

let sum1 = (x: number, y: number) => { return x + y; }
let sum2 = (x: number, y: number) => x + y

9.闭包

(闭包的本质就是想在函数的外部拿到函数内部的值,这就需要返回一个函数,并在该函数的内部来调用需要拿到的变量从而进行锁定变量)

function f(): () => number {
  let count = 0;
  let g = (): number => { count++; return count; };
  //我拿到了 count并把他返回出去从而就劫持了函数内部的count变量
  return g;
}

let z = f();
z(); // 返回:1
z(); // 返回:2

6.类🏃‍♂️🏃‍♀️

类是用于创建对象的模板。他们用代码封装数据以处理该数据。同时类声明也会引入一个新类型,并定义其字段方法构造函数

// 类名 首字母大写(规范)
class 类名{
  // 字段
  
  // 方法
  
  // 构造函数
}


// 使用类 实例化对象 基于类 创建对象
const x:类名 = new 类名()

示例

类声明引入一个新类型,并定义其字段、方法和构造函数。

//在以下示例中,定义了Person类,该类具有字段name和surname、构造函数和方法fullName:
class Person {
  name: string = '';
  surname: string = '';
  constructor (n: string, sn: string) {
    this.name = n;
    this.surname = sn;
  }
  fullName(): string {
    return this.name + ' ' + this.surname;
  }
}
//定义类后,可以使用关键字new创建实例:
let p = new Person('John', 'Smith');
console.log(p.fullName());

可以使用对象字面量创建实例

class Point {
//默认是使用public修饰的
  x: number = 0;
  y: number = 0;
}

let p: Point = {x: 42, y: 42};
//另一种写法,此时已经实例化加赋值了不能加参数了
let p1:Point = new Point()


全面了解ArkTS的类
  1. 实例属性

    通过实例属性(字段)来保存各种类型的数据

// 类
class 类名{
  // 字段名+类型+初始值
  字段名:类型='xxx'
  // 可选字段可以不设置初始值
  字段名?:类型
}

// 可选字段在使用时需要配合 可选链操作符 避免出错
参考代码
class Person {
  name: string = 'jack'
  food?: string
}

const p = new Person()
p.name = 'jack'

console.log(p.name)
console.log('', p.food?.length)

  1. 构造函数

代码在实例化 之后,挨个对属性进行赋值,如果自定义了构造函数,可以在构造函数中完成该操作

class 类{
  字段A:类型
  字段B:类型

  constructor(参数...) {
    // 通过 new 实例化的时候 会调用 constructor
    // 通过关键字 this 可以获取到实例对象
  }
}
const 实例 = new 类()
//------------------案例
interface IFood {
  name: string
  price: number
}

class Food {
  name: string
  price: number

  // constructor(name:string,price:number) {
  //   this.name=name
  //   this.price = price
  // }
  constructor(value: IFood) {
    this.name = value.name
    this.price = value.price
  }
}

// const f = new Food('西兰花炒蛋', 15)
const f = new Food({ name: '花菜炒蛋', price: 10 })

3.实例方法

类中可以定义 方法,并且在内部编写逻辑.这种方法需要通过实例化的对象调用-称之为实例方法

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 Person{
  static staticField:string ='静态字段'
  static staticMethod(){
    console.log('静态方法')
  }
}
Person.staticField
Person.staticMethod()

5.继承,super关键字

类可以通过 继承 快速获取另外一个类的 字段 和 方法。

class 父类 {
  // 字段
  // 方法
  // 构造函数
}

class 子类 extends 父类{
  // 自己的字段(属性)
  // 自己的方法
  // 可以重写父类方法
}

子类通过 super 可以访问父类的实例字段、实例方法和构造函数。可以在适当的时候使用

class 父类 {
  func(){
    
  }
}

class 子类 extends 父类 {

  constructor() {
    super() // 调用父类构造函数
  }
  方法(){
    super.方法() // 调用父类方法
  }
}

class Person {
  name: string
  age: number

  sayHi() {
    console.log(`你好,我叫:${this.name}`)
  }

  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
}

class Student extends Person {
  height: number

  constructor(name: string, age: number, height: number) {
    // name 和 age 的初始化通过 super 来调用父类的构造函数
    super(name, age)
    this.height = height
  }

  sayHi(): void {
    // 通过 super 访问父类的 字段 方法
    super.sayHi()
    super.name
    super.age
    console.log('子类的 sayHi')
  }
}

const s: Student = new Student('jack', 18, 170)

6.instanceof

instanceof 运算符可以用来检测某个对象是否是某个类的实例

// 返回判断结果 布尔值
实例对象 instanceof Class
//试一试
class Person {
  name: string = ''
}

class Student extends Person {
  age: number

  constructor(age: number) {
    super()
    this.age = age
  }
}

const s = new Student(10)
console.log('isStudent', s instanceof Student)
console.log('isPerson', s instanceof Person)
console.log('isArray', [1, 2, 3,] instanceof Array)

const arr = [1, 2, 3]
// 等同于
const arr2 = new Array(1, 2, 3)

7.修饰符

a.readonly(只读)

​ readonly 的意思是只读,可以用来修饰属性(字段),修饰之后外部只可以取值,无法修改

b.private(私有)

​ private修饰的成员不能在声明该成员的类之外访问,包括子类

c.protected(受保护的)

	protected修饰符的作用与private修饰符非常相似,不同点是protected修饰的成员允许在派生类(子类) 	中访问 

d.public(公共)

​ public修饰的类成员(字段、方法、构造函数)在程序的任何可访问该类的地方都是可见的

7.接口🏃‍♀️🏃‍♀️

概述

1.接口声明引入新类型。接口是定义代码协定的常见方式。

2.任何一个类的实例只要实现了特定接口,就可以通过该接口实现多态。

3.接口通常包含属性和方法的声明

interface Style {
  color: string; // 属性
}
interface AreaSize {
  calculateAreaSize(): number; // 方法的声明
  someMethod(): void;     // 方法的声明
}

实现接口的类示例:

// 接口:
interface AreaSize {
  calculateAreaSize(): number; // 方法的声明
  someMethod(): void;     // 方法的声明
}

// 实现:
class RectangleSize implements AreaSize {
  private width: number = 0;
  private height: number = 0;
  someMethod(): void {
    console.log('someMethod called');
  }
  calculateAreaSize(): number {
    this.someMethod(); // 调用另一个方法并返回结果
    return this.width * this.height;
  }
}

接口继承

接口继承使用的关键字是 extends

interface 接口1{
  属性1:类型
}
interface 接口2 extends 接口1 {
  属性2:类型
}
//IVegetable继承了IFood的属性
interface IFood {
  name: string
}

interface IVegetable extends IFood {
  color: string
}

const flower: IVegetable = {
  name: '西兰花',
  color: '黄绿色'
}

接口的实现

可以通过接口结合 implements 来限制 类 必须要有某些属性和方法

interface 接口{
  属性:类型
  方法:方法类型
}

classimplements 接口{
  // 必须实现 接口中定义的 属性、方法,否则会报错
}
//通过接口限制类可以使得类非常的稳定
interface IDog {
  name: string
  bark: () => void
}

class Dog implements IDog {
  name: string = ''
  food: string = ''

  bark() {

  }
}

---------------------------------看到这里了,点点关注和赞吧😘❤❤❤--------------------