鸿蒙开发入门——ArkTS语法简介(万字简介)

ArkTS

作为鸿蒙开发的编程语言,我们先来一图看看这个语言,我们可以看到ArkTS是在TS(TypeScript)的基础上改造的,而TS又是在JS(JavaSript)上改造的,一句话总结就是ArkTS是TS的超集,TS是JS的超集。但ArkTS虽然基于TS,但在某些方面可能施加更严格的类型约束,以适应跨端开发的需求
ArkTS
废话不多说,我们紧接着来说语法,在语法上,其与其他编程语言在语法上并没有很本质的不同,毕竟都是高级的开发编程语言,大家都是有各自的特点,但目的都是为了开发软件,我们就仅在语言层面进行总结

语法

变量类型及变量声明方式

基础的变量声明方式
变量声明

基础数据类型

  • number
  • string
  • boolean

复合数据类型

  • Array(容器类型——还有很多其它的容器如)
    let arr = new Array<string>();
    
  • Object(类型)
    let obj:Object = new Stack<number>();
    
    Object 类型是一个所有非原始类型的基类。原始类型包括 string、number、boolean等内置类型,所以Object 类型可以接收所有非原始类型的值,如对象字面量、数组、函数等
    但要注意在默认情况下,ArkTS中所有类型都不允许赋值为null或undefined

其它特殊类型

  • 联合类型
    联合类型即给声明能够接受多种类型的变量,通过竖线(“|”)将不同的类型联合起来,自定义类型也可以联合

    class Cat {
    // ...
    }
    class Dog {
    // ...
    }
    class Frog {
    // ...
    }
    type Animal = Cat | Dog | Frog | number
    // Cat、Dog、Frog是一些类型(类或接口)let animal: Animal = new Cat();
    animal = new Frog();
    animal = 42;
    // 可以将类型为联合类型的变量赋值为任何组成类型的有效值
    
  • void类型
    一般void类型都是用于作为函数返回值

  • null和undefined

    • null类型主要表示空值,用于明确表示一个变量没有指向任何对象或暂时不知道给什么具体值
    • undefined主要表示一个变量声明了但还未赋值,如在函数使用了可选参数未传递时则该参数的值就为undefined

    总结来说,null是一个明确的“空”值,而undefined表示一个变量或值尚未被定义或赋值。

  • enum类型
    枚举类型即包含一组常量的集合,如

    enum Color {  Red,  Green,  Blue  
    }
    

    定义了该类型后可以在声明类型时使用该类型进行声明,如

    let favoriteColor: Color = Color.Green;  
    console.log(favoriteColor); // 输出:1
    
  • 元组类型(tuple)
    本质也是一个数组,不过是知道元素类型的数组,如:

    let tuple: [string, number, boolean] = ["hello", 42, true];
    

    访问元素时也是通过数组下标进行访问,不过需要注意对应的类型匹配,元组的元素数量和类型必须与定义时一致,否则会导致编译错误。
    tuple实例

补充说明

  • 匿名类型(起别名):type
    Aliases类型为匿名类型(数组、函数、对象字面量或联合类型)提供名称,或为已有类型提供替代名称
    type int = number;
    let i: int = 1;
    type Matrix = number[][];
    type Handler = (s: string, no: number) => string;
    type Predicate <T> = (x: T) => Boolean;
    type NullableObject = Object | null;
    
  • tips:注意在ArkTS中,类型都必须指明,但在TS中可以使用any关键字接收任意类型的变量,需要注意区分any
  • 空值安全
    上面说过了,默认情况下,ArkTS中的所有类型都是不可为空的,因此类型的值不能为空,当使用的变量为空或者有可能为空时,编译器都会报错,但一些情况下我们也要赋空值或undefined,下面情况说明了如何在ArkTS中能够使用空值和undefined初始化变量
    • 使用非空断言运算符(!):紧接在变量后使用"!",判断变量为空时则不使用该值,不为空时则使用该值
    class C {value: number | null = 1;
    }let c = new C();
    let y: number;
    y = c.value + 1;  // 编译时错误:无法对可空值作做加法
    y = c.value! + 1; // ok,值为2
    // 若c.value为空时则值为1
    
    • 空值合并运算符(??):a ?? b等价于三元运算符(a != null && a != undefined) ? a : b,即如果a为空或undefined时则值等于b,否则值等于a
    • 可选链(后缀运算符?):在访问某个变量时,在其后加个"?“,访问时则会判断其是否为null或undefined,如果是则返回undefined,不是则访问该变量。在一些类中声明变量时在其后加个”?"也表示该变量可为undefined
    // 如果一个Person的实例有不为空的spouse属性,
    // 且spouse有不为空的nick属性,则输出spouse.nick。否则,输出undefined
    class Person {nick: string | null = nullspouse?: Personconstructor(nick: string) {this.nick = nick;this.spouse = undefined;}
    }let p: Person = new Person('Alice');
    console.log(p.spouse?.nick); // undefined)p.spouse = p;
    console.log(p.spouse?.nick);
    

其它部分常用语句

此处仅列举与C++有些区别的语句

for

  • 一般的循环:for(let i = 0; i < 10; i+= 2){…}

  • 范围for: for (forVar of expression) {statements}

    forVar: expression的一个元素;expression:一个“容器” 如:

    for (let ch of 'a string object') {/* process ch */}

break

一般正常使用
如果break语句后带有标识符,则将控制流转移到该标识符所包含的语句块之外。如:

let x = 1
label: while (true) {  switch (x) {case 1:      // statements      break label // 中断while语句  }
}

函数

函数的声明

函数声明中,函数的返回值类型可以省略
tips:返回值的类型也可以是一个联合类型
函数声明

函数参数

  • 可选参数:name?:type
    此处的name如果未传入则是undefined
    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);  // 返回22
    multiply(2, 3); // 返回23
    
  • 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
    // 使用Object类型时的数组,可传入多种不同类型的参数,都会保存到给的数组里
    function exampleFunction(...args: Object[]) {args.forEach(arg => {console.log(arg.toString());});
    }exampleFunction(1, 'string', true);
    

函数类型——箭头函数(lambda表达式)

lambda表达式

语法:(参数列表):返回值=>{函数体}
我们可以将函数类型保存:type trigFunc = (x: number) => number // 这是一个函数类型
lambda的返回值可省略,返回值省略时根据函数体推导返回值,函数体仅一行时可以去掉大括号,所以指向类型为number时说明返回值的类型是number,代码含义即为一个函数类型为参数是一个number类型,返回值为number类型的函数

函数闭包

即在函数体内部又包含一个函数,那么这个函数从声明到内部这包含的另一个函数之间的作用域的变量会被保存下来(类似变成了局部全局)

function f(): () => number {let count = 0;let g = (): number => { count++; return count; };return g;
}let z = f();
z(); // 返回:1
z(); // 返回:2

函数重载

函数重载(重载方式与其它语言不完全相同,实现只能有一个,定义可以重载多个,即签名。注意这里的参数也可以使用联合类型)

function foo(x: number): void;            /* 第一个函数定义 */
function foo(x: string): void;            /* 第二个函数定义 */
function foo(x: number | string): void {  /* 函数实现 */
}foo(123);     //  使用第一个定义
foo('aa'); // 使用第二个定义

类的基本操作都与C++相似,通过上面的变量、函数的内容即可封装一个类,下面主要介绍一些不同的地方

关于封装

ArkTS中,要求所有成员必须在声明时就进行定义初始化(或在构造函数中进行初始化),即所有字段在声明时或者构造函数中显式初始化
但也可以通过可选链的方式表示为undefined,但此时使用值时则需要对应注意
封装的说明

getter和setter

在类内实现getter和setter时,首先可以使用deveco一键生成
我们要关注一点的是此处生成的函数形式是get/set 属性(): 返回类型{return 返回值} 而不是一般的声明函数的方式,如:

class Person {name: string = ''private _age: number = 0get age(): number { return this._age; }set age(x: number) {if (x < 0) {throw Error('Invalid age argument');}this._age = x;}
}let p = new Person();
p.age; // 输出0
p.age = -42; // 设置无效age值会抛出错误

构造函数

构造函数在实现上与其他语言也大体相似,未提供构造时默认会自动创建具有空参数列表的默认构造函数
但需要注意的是,构造函数也可以重载多个形式,但与函数重载相同,重载时实现在类中只能有一个,重载定义可以有多个,如:

class C {constructor(x: number)             /* 第一个签名 */constructor(x: string)             /* 第二个签名 */constructor(x: number | string) {  /* 实现签名 */}
}
let c1 = new C(123);      // OK,使用第一个签名let c2 = new C('abc');    // OK,使用第二个签名
// 以下方式则是错误的
class A{constructor(x: number) {}constructor(x: string) {}
}

关于类的实例创建

  • 类都是使用new进行实例的创建
    可以直接使用构造函数构建实例对象

    let p = new Person('John', 'Smith');
    console.log(p.fullName());class Point {x: number = 0y: number = 0
    }
    let p: Point = {x: 42, y: 42};
    
  • 静态字段:使用static声明变量即可(而不是用let或const)

  • 继承
    继承时,父类中受访问限定符成员也会相同继承到子类

    • 使用extends进行继承,只能继承一个类
      但可以通过继承接口来继承多个接口,使用implements
      • 一个类,可以同时继承某一个类之后再继承多个接口
      • 继承接口时,必须实现接口内定义的所有方法(除非接口内的方法已有默认实现)
    • 在子类中,父类通过super进行访问,super即代表了父类的实例
      • 在继承类了父类的子类中,构造函数第一行必须通过super(…)显式的调用父类的构造函数,当然如果不提供构造函数,会使用默认生成的构造函数,其会自动去调用父类的构造函数
    • 关于继承后的方法重写
      • 重写本质是为了形成多态
      • 重写时需要与被重写的方法具有相同的方法名、参数类型与返回类型
    • 类中的重载——本质也和arkts的函数重载相同,只能重载定义(建立签名),实现只能有一个。重载的函数的名称和参数列表不能均相同
  • 多态在继承后直接重写同名函数即可

  • 类的创建

    • 直接使用new创建对象
    • 关于对象字面量:封闭在花括号对({})中的’属性名:值’的列表。
      • 使用{…}(对象字面量)创建,内部的参数为类内的成员(按照顺序进行初始化)
        但是要确保对象字面量的结构符合类的结构,但并没有创建类的实例。

      • 对象字面量只能可以推导出该字面量类型的上下文中使用。其他正确的例子:

        class C {n: number = 0s: string = ''
        }let c: C = {n: 42, s: 'foo'};// 若类C为下述方式,则无法保证对应的对象字面量是C类的实例
        class C {a: number = 0;b: string = '';constructor(a: number, b : string) {}
        }
        
  • Record类型(就是哈希表的一种,但该语言中也有Map类型)
    let hash = new Map<Number, string>();//哈希表类型

    泛型Record<K, V>用于将类型(键类型)的属性映射到另一个类型(值类型)

    • Key只能是字符串或数值类型,但Value可以是任意类型

    tips:使用时需要先进行初始化

    // 创建一个哈希表
    let hashTable: NumberStringHashTable = {};
    // 访问和修改哈希表中的值
    console.log(hashTable[1]); 
    // 输出: onehashTable[1] = 'ONE';
    console.log(hashTable[1]); // 输出: ONE
    // 添加新的键值对
    hashTable[4] = 'four';
    // 遍历哈希表
    Object.keys(hashTable).forEach(key => {\console.log(`${key} = ${hashTable[key]}`);
    

接口

  • 接口的声明
    • 使用interface关键字
    • 接口可以继承其他接口,其他类继承可以继承多个接口(implements)
    • 接口中的函数声明可以不使用(省略掉)function关键字

泛型编程(模板)

用于定义模板类、模板接口以及模板函数等,直接用尖括号表示即可

  • 模板类和接口

    class CustomStack<Element> {public push(e: Element):void {// ...}
    }
    // 要使用类型CustomStack,必须为每个类型参数指定类型实参
    let s = new CustomStack<string>();
    s.push('hello');
    // 在使用泛型类型和函数时会确保类型安全
    s.push(55); // 将会产生编译时错误
    
  • 泛型类型的类型参数可以绑定.例如,HashMap<Key, Value>容器中的Key类型参数必须具有哈希方法,即它应该是可哈希的。

    即通过继承接口的方式,使得对应的泛型参数(类型)在传递过来时必须实现对应的接口,
    Key 类型参数被约束为 Hashable 接口的实现。这意味着只有那些实现了 hash 方法的类型才能用作这个哈希映射的键。

    interface Hashable {hash(): number
    }
    class HasMap<Key extends Hashable, Value> {public set(k: Key, v: Value) {let h = k.hash();// ...其他代码...}
    }
    
  • 泛型函数

    语法:function last<T>(x: T): T

    在函数名后加上尖括号,之后即可在参数列表、返回类型以及函数体中使用对应的模板参数

    返回数组最后一个元素的函数

    function last(x: number[]): number {return x[x.length - 1];
    }
    last([1, 2, 3]); // 3
    // 模板函数:
    function last<T>(x: T[]): T {return x[x.length - 1];
    }
    
  • 泛型的默认值

    在泛型的类型参数可以设置默认值,此时使用时则可以不指定泛型的形参而直接使用泛型类型的名称,如下

    class SomeType {}
    interface Interface <T1 = SomeType> { }
    class Base <T2 = SomeType> { }
    class Derived1 extends Base implements Interface { }
    // Derived1在语义上等价于Derived2
    class Derived2 extends Base<SomeType> implements Interface<SomeType> { }function foo<T = number>(): T {// ...
    }
    foo();
    // 此函数在语义上等价于下面的调用
    foo<number>();
    

模块

常见的为ets文件中的模块的导入与导出

模块即可以理解是一个作用域,小到函数体、类,大到文件等,每个模块都有自己的作用域,该模块之外都不可见,除非被显式导出

与此相对,从另一个模块导出的变量、函数、类、接口等必须首先导入到模块中

  • 导出(类、变量、函数都可导出)

    • 通过export关键字导出
    • 未导出的声明名称被视为私有名称,只能在声明该名称的模块中使用(没导出就不能四处用)

    注意:通过export方式导出,在导入时要加{}。

    export class Point {x: number = 0y: number = 0constructor(x: number, y: number) {this.x = x;this.y = y;}
    }
    export let Origin = new Point(0, 0);
    export function Distance(p1: Point, p2: Point): number {return Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
    }
    
  • 导入

    • 静态导入

      即直接使用导入声明对想要的模块直接先进行导入,导入声明用于导入从其他模块导出的实体,并在当前模块中提供其绑定。导入声明由两部分组成:

      • 导入路径,用于指定导入的模块;
      • 导入绑定,用于定义导入的模块中的可用实体集和使用形式(限定或不限定使用)
      • 导入形式
        1. 直接导入,并且绑定名称

          import * as Utils from './utils'
          Utils.X // 表示来自Utils的X
          Utils.Y // 表示来自Utils的Y
          
        2. 绑定对应的导入实体名称

          import { X, Y } from './utils'
          X // 表示来自utils的X
          Y // 表示来自utils的Y
          
        3. 给绑定的导入实体起别名

          import { X as Z, Y } from './utils'
          Z // 表示来自Utils的X
          Y // 表示来自Utils的Y
          X // 编译时错误:'X'不可见
          
    • 动态导入(后续再进行详解)

      动态导入即是根据条件导入模块(或按需导入),使用import()语法实现

      import()语法通常称为动态导入dynamic import,是一种类似函数的表达式,用来动态导入模块。以这种方式调用,将返回一个promise。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1483835.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

新版本 idea 创建不了 spring boot 2 【没有jkd8选项】

创建新项目 将地址换成如下 https://start.aliyun.com/

HackQuest介绍 web3 学习平台

HackQuest 官网地址&#xff1a; https://www.hackquest.io/zh HackQuest是一个专注于Web3技术教育的在线学习平台&#xff0c;旨在帮助全球开发者掌握区块链、加密货币和去中心化应用&#xff08;DApps&#xff09;领域的最新技能。该平台汇聚了超过14000名活跃开发者&#…

C学习(数据结构)-->单链表习题

目录 一、环形链表 题一&#xff1a;环形链表 思路&#xff1a; 思考一&#xff1a;为什么&#xff1f; 思考二&#xff1a;快指针一次走3步、4步、......n步&#xff0c;能否相遇 step1&#xff1a; step2&#xff1a; 代码&#xff1a; 题二&#xff1a; 环形链表 I…

区块链技术在溯源领域的应用

区块链技术具有去中心化、不可篡改、可追溯等特点&#xff0c;使其在溯源领域具有广阔的应用前景。具体而言&#xff0c;区块链技术可以应用于以下几个方面。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1. 产品溯源 产品溯源是指…

Nginx的核心功能

1. Nginx的核心功能 1.1 nginx反向代理功能 正向代理 代理的为客户端&#xff0c;对于服务器不知道真实客户的信息。例如&#xff1a;翻墙软件 反向代理服务器 代理的为服务器端。对于客户来说不知道服务器的信息。例如&#xff1a;nginx 项目部署图 web项目部署的虚拟机和Ng…

【linux】服务器安装NVIDIA驱动

【linux】服务器安装NVIDIA驱动 【创作不易&#xff0c;求点赞关注收藏】&#x1f600; 文章目录 【linux】服务器安装NVIDIA驱动一、关闭系统自带驱动nouveau二、下载英伟达驱动三、安装英伟达驱动1、禁用X服务器和相关进程2、在TTY终端安装驱动3、验证是否安装成功4、重新启…

HarmonyOS根据官网写案列~ArkTs从简单地页面开始

Entry Component struct Index {State message: string 快速入门;build() {Column() {Text(this.message).fontSize(24).fontWeight(700).width(100%).textAlign(TextAlign.Start).padding({ left: 16 }).fontFamily(HarmonyHeiTi-Bold).lineHeight(33)Scroll() {Column() {Ba…

Spring循环依赖与三级缓存

Spring循环依赖是指两个或多个Bean相互依赖&#xff0c;导致Spring无法在不部分实例化这些Bean的情况下完成它们的创建。在Spring框架中&#xff0c;为了解决循环依赖问题&#xff0c;Spring使用了三级缓存机制。 假设BeanA依赖BeanB&#xff0c;BeanB依赖BeanA&#xff0c;Spr…

Nginx详解(超级详细)

目录 Nginx简介 1. 为什么使用Nginx 2. 安装Nginx Nginx的核心功能 1. Nginx反向代理功能 2. Nginx的负载均衡 3 Nginx动静分离 Nginx简介 Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;在BSD-like 协…

2-35 基于matlab的四足液压机器人设计程序

基于matlab的四足液压机器人设计程序&#xff0c;界面化例程&#xff0c;输入液压机器人结构参数&#xff0c;输出液压缸的行程、推力和速度。程序已调通&#xff0c;可直接运行。 2-35 四足液压机器人 液压机器人结构参数 - 小红书 (xiaohongshu.com)

Postman、Apifox、Apipost用哪个?

Postman、Apifox、Apipost都是流行的API接口管理工具&#xff0c;它们各自具有不同的特点和优势&#xff0c;因此哪个更好用取决于具体的使用场景和需求。以下是对这三个工具的比较分析&#xff1a; 一、Postman 特点与优势&#xff1a; 支持多种请求方式&#xff1a;包括GE…

基于Python+Django+MySQL的心理咨询预约系统

心理咨询预约系统 DjangoMySQL 基于PythonDjangoMySQL的心理咨询预约系统 项目主要依赖Django3.2&#xff0c;MySQL 支持随机验证码生成与登录验证 简介 基于PythonDjangoMySQL的心理咨询预约系统通过连接数据库获取数据&#xff0c;登录新增随机数字验证码验证。具体可以看…

VisualRules-Web案例展示(一)

VisualRules单机版以其卓越的功能深受用户喜爱。现在&#xff0c;我们进一步推出了VisualRules-Web在线版本&#xff0c;让您无需安装任何软件&#xff0c;即可在任何浏览器中轻松体验VisualRules的强大功能。无论是数据分析、规则管理还是自动化决策&#xff0c;VisualRules-W…

GESP CCF C++ 四级认证真题 2024年6月

第 1 题 下列代码中&#xff0c;输出结果是&#xff08; &#xff09; A. 12 24 24 12 B. 24 12 12 24 C. 12 12 24 24 D. 24 24 12 12 第 2 题 下面函数不能正常执行的是&#xff08;&#xff09; A. B. C. D. 第 3 题 下面程序…

理解UI设计:UI设计师的未来发展机遇

UI设计师的出现是互联网时代的设计变革。随着移动互联网的快速发展&#xff0c;移动产品设计师非常短缺。高薪资让许多其他行业的设计师已经转向了UI设计。那么什么是UI设计呢&#xff1f;UI设计师负责什么&#xff1f;UI设计的发展趋势和就业前景如何&#xff1f;这些都是许多…

JMX 反序列化漏洞

前言 前段时间看到普元 EOS Platform 爆了这个洞&#xff0c;Apache James&#xff0c;Kafka-UI 都爆了这几个洞&#xff0c;所以决定系统来学习一下这个漏洞点。 JMX 基础 JMX 前置知识 JMX&#xff08;Java Management Extensions&#xff0c;即 Java 管理扩展&#xff0…

PyTorch 深度学习实践-加载数据集

视频指路 参考博客笔记 参考笔记二 目录标题 介绍课程代码作业实现 介绍 在深度学习时用min-batch来平衡训练时间和性能上的需求&#xff0c;之后训练周期要写成两层嵌套循环。epoch&#xff1a;所有训练样本进行完一次前向和反向传播&#xff0c;batch-size&#xff1a;训练的…

Yolo-World网络模型结构及原理分析(更新中)

文章目录 概要一、整体架构分析二、详细结构分析1.YOLO检测器1.1 Backbone1.2 Head1.3 各模块的过程和作用Conv卷积模块C2F模块BottleNeck模块SPPF模块Upsampling模块Concat模块 2.文本编码器 Text Encoder 概要 尽管YOLO&#xff08;You Only Look Once&#xff09;系列的对象…

AI(Adobe lliustrator)教程+软件包

简介&#xff1a; 软件主要应用于印刷出版、海报书籍排版、专业插画、多媒体图像处理和互联网页面的制作等&#xff0c;也可以为线稿提供较高的精度和控制&#xff0c;适合生产任何小型设计到大型的复杂项目。 通常用于创建LOGO(商标或徽标)&#xff0c;图标&#xff0c;插图…

实践之K近邻算法实现红酒聚类

前言 K近邻算法是一种用于分类和回归的非参数统计方法&#xff0c;通过计算样本与训练样本的距离&#xff0c;找出最接近的k个样本进行投票来确定分类结果。算法的基本要素包括K值、距离度量和分类决策规则。 K值决定了邻居的影响程度&#xff0c;距离度量反映了样本间的相似度…