# 1.2:OpenHarmony开发语言简介

OpenHarmony 为应用开发提供了一套 UI 开发框架,即方舟开发框架(ArkUI开发框架),ArkUI开发框架针对不同技术背景的开发者提供了两种开发范式,分别是基于 JS 扩展的类 Web 开发范式和基于 TS 扩展的声明式开发范式,它们之间的简单对比如下所示:

名称 语言 UI更新方式 使用场景 使用对象
类Web开发范式 JS语言 数据驱动更新 界面较为简单的程序应用和卡片 Web前端开发人员
声明式开发范式 扩展的TS语言 数据驱动更新 复杂度较大、团队合作度较高的程序 移动系统应用开发人员、系统应用开发人员

以上两种开发范式都提供了丰富的UI组件,这些组件的底层由 C++ 实现,读者可在 ACE (opens new window) 仓里阅读各组件的实现源码,采用 C++ 实现的好处之一是可以方便对接其它语言的UI框架。比如华为自研的编程语言仓颉,仓颉定义一套UI框架,经过方舟编译器编译成 abc 后可直接调用 ACE 的实现。

笔者十分期待仓颉的发布,到那个时候我们有自己的编程语言 + 编译器 + OpenHarmony,如果芯片领域取得突破(芯片架构 + 芯片制程),那么在计算机领域我们的基础底座就无惧任何打压和封锁了,相信这一天很快会到来……

UI框架的发展趋势,从 Android 和 iOS 的发展历程看,Android 从 View 框架到 Jetpack Compose,iOS 的 UIKits 到 SwiftUI,都是由命令式UI往声明式UI发展,如果仓颉推出的UI框架底层对接的是 ACE ,那么也应该是声明式UI框架,并且和ArkUI框架的声明式UI的语法很类似,因此本书笔者只介绍基于 TS 扩展的声明式开发方式。

# 1.2.1:什么是TS?

TypeScript 简称 TS ,它是 JavaScript 的一个超集并支持 ECMAScript 6 标准,如果读者已经熟悉 TS 语法可以直接跳过本节了,如果有过其它编程语言经验的话会很容易上手,语言都是相通的,充其量就是熟悉一下不同语言间的语法,本节只是简单介绍一下 TS 语法,如果想更多的了解 TS,请自行查看 TypeScript 官网 (opens new window)

# 1.2.2:基础类型

  1. Any

    TypeScript 提供了 any 关键字表示任意数据类型,声明为该类型的变量可以赋予任意类型的值。

    var data: any;                        // 声明data为any类型
    data = true;
    console.log(typeof data);             // boolean
    data = 'OpenHarmony';
    console.log(typeof data);             // string
    data = 100;
    console.log(typeof data);             // number
    data = 10.5
    console.log(typeof data);             // number
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
  2. number

    TypeScript 提供了 number 关键字来表示数字类型,它是双精度 64 位浮点值,既可以表示整数,又可以表示小数。

    var data: number;
    data = 100;
    console.log(typeof data)             // number
    data = -10;
    console.log(typeof data)             // number
    data = 3.14;
    console.log(typeof data)             // number
    data = 0b10001;
    console.log(typeof data)             // number
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
  3. string

    TypeScript 提供了 string 关键字来表示字符串类型,使用单引号(')或双引号(")来表示字符串类型,也可以使用反引号(`)来定义多行文本和内嵌表达式。

    var data: string;
    data = "Hello, OpenHarmony";
    data = 'Hello, OpenHarmony';
    data = `Hello, ${data}`
    console.log(data)                    // Hello, Hello, OpenHarmony
    
    1
    2
    3
    4
    5
  4. boolean

    TypeScript 提供了 boolean 关键字来表示逻辑值 true 和 false。

    var data: boolean = false;
    data = true;
    data = false;
    
    1
    2
    3
  5. 数组类型

    TypeScript 没有提供专门的关键字来表示数组类型,声明一个数组可以使用元素类型后边加**[]**或者数组泛型的方式。

    var scores: number[] = [90, 88];                      // 声明一个number数组
    var names: string[] = ["张三", "李四"];                // 声明一个string数组
    var address: Array<string> = ["Beijing", "Tianjin"];  // 声明一个string数组
    console.log(names[0])                                 // 访问数组
    console.log(scores[0].toString())                     // 访问数组
    console.log(address[0])                               // 访问数组
    
    for(var i = 0; i < address.length; i++) {             // 遍历数组
      console.log(address[i])
    }
    
    for(var index in address) {                           // 遍历数组
      console.log(address[index])
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  6. 元组

    TypeScript 提供了元组来表示已知元素数量和类型的数组,元组内的各元素的类型不必相同,但是对应位置的类型必须一致。

    var user: [string, number, string]; // 定义一个元组
    user = ["张三", 18, 'Beijing'];      // 初始化元组,对应位置类型必须一致
    console.log(`姓名:${user[0]}`)      // 姓名:张三
    console.log(`年龄:${user[1]}`)      // 年龄:18
    console.log(`住址:${user[2]}`)      // 住址:Beijing
    
    1
    2
    3
    4
    5
  7. enum

    TypeScript 提供了 enum 关键字表示枚举类型,枚举类型主要用于定义数值的集合。

    enum Color {               // 定义一个枚举
      Red,
      Green,
      Blue
    }
    var c: Color = Color.Blue; // 定义枚举类型
    console.log(c.toString()); // 2
    
    1
    2
    3
    4
    5
    6
    7
  8. void

    TypeScript 提供了 void 关键字表示函数的返回类型为空,也就是函数没有返回值。

    function print(msg: string): void { // 函数没有返回值
      console.log(msg)
    }
    
    1
    2
    3
  9. undefined

    TypeScript 提供了 undefined 关键字表示声明了一个变量但并没有赋值的情况。

    var data;                 // 声明了data,但是没有赋值
    console.log(typeof data); // undefined
    
    1
    2
  10. null

    TypeScript 提供了 null 关键字表示一个对象没有初始化。

    class Person {
    }
    
    var person: Person;              // 声明一个person,但是没有初始化
    if(null == person) {
      console.log("person is null"); // person is null
    }
    
    1
    2
    3
    4
    5
    6
    7
  11. 联合类型

    TypeScript 允许通过 | 将一个变量设置成多种类型,赋值的时候可以根据设置的类型来赋值。

    var data: string | number; // 设置data为联合类型
    data = 'OpenHarmony';      // 正确
    data = 99;                 // 正确
    data = true;               // 编译报错,类型不匹配
    
    1
    2
    3
    4

    📢:联合类型很重要,ArkUI框架里大量使用了联合类型。

# 1.2.3:变量声明

  1. var

    变量在使用前必须先声明,TS 使用 var 声明一个变量,我们可以使用一下四种方式来声明变量:

    • 声明变量的类型并赋值初始值,格式:var [变量名] : [类型] = 值;

      var osName:string = "OpenHarmony";
      
      1
    • 声明变量的类型但不赋值初始值,格式:var [变量名] : [类型];

      var osName:string;
      
      1
    • 声明变量并赋值初始值,但不设置类型,格式:var [变量名] = 值;

      var osName = "OpenHarmony";
      
      1
    • 声明变量并没有设置类型和初始值,该类型可以是任意类型,默认值为 undefined,格式:var [变量名];

      var osName;
      
      1

    简单样例如下:

    var osName: string = "OpenHarmony";
    var price1: number = 5;
    var price2: number = 5.5
    var sum = price1 + price2
    console.log("操作系统名字: " + osName); // 操作系统名字: OpenHarmony
    console.log("第一个价格是: " + price1); // 第一个价格是: 5
    console.log("第二个价格是: " + price2); // 第二个价格是: 5.5
    console.log("总价格: " + sum);         // 总价格: 10.5
    
    1
    2
    3
    4
    5
    6
    7
    8

    📢:TypeScript 遵循强类型,如果将不同的类型赋值给变量会编译错误,样例如下:

    var count: number = "hello"; // 这个代码会编译错误
    
    1

# 1.2.4:函数

  1. 函数声明

    函数就是包裹在花括号中的代码块,前边使用 function 关键字,语法格式如下:

    function function_name() {
      // 执行代码
    }
    
    1
    2
    3

    例如声明函数如下:

    function log(msg: string) { // 声明一个函数
      console.log(msg);         // 代码块
    }
    
    1
    2
    3
  2. 函数调用

    函数只有通过调用才可以执行函数内的代码,语法格式如下:

    function_name()
    
    1

    样例如下:

    function log(msg: string) { // 声明一个函数
      console.log(msg);         // 代码块
    }
    log("Hello, OpenHarmony");  // 调用函数
    
    1
    2
    3
    4
  3. 函数返回值

    如果希望得到函数的执行结果,可以使用 return 语句,语法如下:

    function function_name(): return_type {
        return value; // return语句
    }
    
    1
    2
    3

    样例如下:

    function sayHi():string { // 定义sayHi函数,该函数的返回类型为string
        return "Hello!" 
    }
    
    function execute() {      // 定义execute函数
        var msg = sayHi();    // 调用sayHi()函数
        console.log(msg);     // 打印sayHi()函数的返回值
    }
    
    execute();                // 调用execute()函数
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  4. 带参数函数

    在调用函数时可以向函数传递值,这些值被称为参数,语法如下:

    function func_name(param1 :paramType, param2 :paramType) {
    }
    
    1
    2

    样例如下:

    function add(x: number, y: number): number { // 定义add函数,该函数返回类型为nubmer, 接收两个number类型的参数x
        return x + y;
    }
    
    console.log(add(1,2))                        // 3
    
    1
    2
    3
    4
    5
  5. 可选参数

    如果函数定义了参数则必须传递这些参数否则报错,如果不想传递这些参数,可以添加 ? ,语法如下:

    function func_name(param1: paramType, param2?: paramType) {
    }
    
    1
    2

    样例如下:

    function add(x: number, y?: number) {
      if (y) {
        return x + y;
      } else {
        return x;
      }
    }
    
    console.log(add(10).toString());     // 10
    console.log(add(10, 10).toString()); // 20
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    📢:如果参数不全是可选参数,那么可选参数的位置必须放在最后。

  6. 默认参数

    函数定义了参数则必须传递这些参数否则报错,如果不想传递这些参数除了使用可选参数外,也可以使用默认参数,当不传入该参数时则使用默认值,语法如下:

    function func_name(param1: paramType, param2: paramType = default_value) {
    }
    
    1
    2

    样例如下:

    function add(x: number = 20, y: number = 50) { // 设置x和y的默认值
      return x + y;
    }
    
    console.log(add(10).toString());               // 60
    console.log(add(10, 10).toString());           // 20
    
    1
    2
    3
    4
    5
    6

    📢:函数的参数不能同时是默认参数和可选参数。

  7. 剩余参数

    在不确定要向函数传递多个参数的情况下,可以使用剩余参数,剩余参数前边以 ... 为前缀数据类型为数组的形式提供,语法如下:

    function func_name(param1: paramType, param2: paramType, ...params: paramType[]) {
    }
    
    1
    2

    样例如下所示:

    function add(param1: number, param2: number, ...params: number[]) { // 剩余参数
      var result = param1 + param2;
      for(var i = 0; i < params.length; i++) {  // 遍历剩余参数
        result += params[i];
      }
      return result;
    }
    
    console.log(add(1, 2, 3, 4, 5).toString()); // 15
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

# 1.2.5:类

  1. 定义类

    TypeScript 是面向对象的 JavaScript,定义一个类使用关键字 class ,类可以包含字段、构造方法和方法。语法如下:

    class class_name {
      // 类作用域
    }
    
    1
    2
    3

    样例如下:

    class Person {
      name: string;
      age: number;
    
      constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
      }
    
      info(): string {
        return "name: " + this.name + ", age: " + this.age;
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
  2. 创建类对象

    类定义完后,可以通过 new 关键字实例化一个类的对象,实例化类对象即调用类的构造方法,语法如下:

    var object_name = new class_name([ args ])
    
    1

    样例如下:

    var person = new Person('harmony', 10); // 创建一个Person对象
    
    1
  3. 访问类属性和方法

    访问类的属性和方法以 . 号的形式,语法如下:

    obj.field_name      // 访问属性
    obj.function_name() // 访问方法
    
    1
    2

    样例如下:

    var person = new Person('harmony', 10); // 创建一个person
    
    console.log(person.name);               // harmony
    console.log(person.age.toString());     // 10
    console.log(person.info());             // name: harmony, age: 10
    
    1
    2
    3
    4
    5
  4. 类的继承

    TypeScript 支持继承类,创建类的时候可以使用关键字 extends 继承一个已有的类,这个已有的类称为父类,继承它的类称为子类。子类除了不能继承父类的私有成员(方法和属性)和构造函数,其他的都可以继承。语法如下:

    class child_class_name extends parent_class_name {
    }
    
    1
    2

    样例如下:

    class Zhangsan extends Person {
      sayHello() {
        console.log("Hello, " + this.name)
      }
    }
    
    var person = new Zhangsan('harmony', 10); // 创建person
    
    console.log(person.name);                 // harmony
    console.log(person.age.toString());       // 10
    console.log(person.info());               // name: harmony, age: 10
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    📢:类的继承只支持单继承,不支持多继承。也就是说子类只能继承一个父类。

  5. 方法重写

    子类可以重写父类的方法,在重写父类方法的时候也可以使用 super 关键字调用父类的方法。样例如下:

    class Zhangsan extends Person {
    
      info(): string {                        // 重写父类方法
        console.log(super.info());            // 调用父类方法
        return "Hello, " + this.name;         // 重新实现info方法
      }
    }
    
    var person = new Zhangsan('harmony', 10);
    
    console.log(person.name);                 // harmony
    console.log(person.age.toString());       // 10
    console.log(person.info());               // name: harmony, age: 10
                                              // Hello, harmony
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  6. 访问修饰符

    TypeScript 中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。TypeScript 支持 3 种不同的访问权限。

    • public(默认):公有,可以在任何地方被访问。

    • protected:受保护,可以被其自身以及其子类访问。

    • private:私有,只能被其定义所在的类访问。

      样例如下所示:

      class Person {
        name: string;
        private age: number;                  // age为private,外界无法访问
      
        constructor(name: string, age: number) {
          this.name = name;
          this.age = age;
        }
      
        info(): string {
          return "name: " + this.name + 
            ", age: " + this.age;
        }
      }
      
      var person = new Person('harmony', 10);
      console.log(person.name);               // harmony
      console.log(person.age.toString());     // 编译报错,age为private
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18

# 1.2.6:接口

  1. 定义接口

    接口是一系列抽象方法的声明,接口定义后需要具体的类实现,语法如下:

    interface interface_name {
      // 抽象方法
    }
    
    1
    2
    3

    样例如下:

    interface IPerson {        // 定义一个接口
      name: string;            // 定义接口的一个属性
      say: () => string;       // 定义接口的一个方法
    }
    
    var person: IPerson = {    // 创建一个接口的实例
      name: "OpenHarmony",     // 设置属性值
      say: () => {             // 实现接口方法
        return "Hello, " + person.name;
      }
    }
    
    console.log(person.name);  // OpenHarmony
    console.log(person.say()); // Hello, OpenHarmony
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  2. 接口继承

    接口可以使用 extends 关键字继承其它接口来扩展自己,接口既支持单继承又支持多继承,多继承时接口间使用逗号 , 分隔。语法如下:

    // 接口单继承
    interface Child_interface_name extends super_interface_name {
    }
    
    // 接口多继承
    interface Child_interface_name extends super_interface_name1, super_interface_name2 {
    }
    
    1
    2
    3
    4
    5
    6
    7

    样例如下:

    interface IPerson {                  // 定义接口IPerson
      name: string;
      say: () => string;
    }
    
    interface ITeacher extends IPerson { // 定义接口ITeacher并继承IPerson
      age: number;
      teach: () => void;
    }
    
    var teacher = <ITeacher>{};
    teacher.name = "张三";
    teacher.age = 18;
    teacher.say = () => {
      return "你好,我是" + teacher.name;
    }
    teacher.teach = () => {
      console.log("同学们好,我们开始上课啦")
    }
    
    console.log("name: " + teacher.name);
    console.log("age : " + teacher.age);
    console.log("say :" + teacher.say());
    teacher.teach();
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
  3. 类实现接口

    类可以使用 implements 关键字实现一个接口,一个类实现接口后必须声明和实现接口的所有属性和方法。

    interface IPerson {                        // 定义一个接口
      name: string;                            // 定义接口的属性
      say: () => string;                       // 定义接口的方法
    }
    
    class Person implements IPerson {          // 类型实现接口
      name: string;                            // 必须声明接口属性
      constructor(name: string) {              // 在构造方法对属性初始化
        this.name = name;
      }
    
      say(): string {                          // 实现接口的方法
        return `Hello, I'm ${this.name}`;
      }
    }
    
    class Teacher implements IPerson {         // 类型实现接口
    
      constructor(public name: string) {       // 声明接口属性简化方式
      }
    
      say(): string {                          // 实现接口的方法
        return `Hello, I'm ${this.name}`;
      }
    }
    
    var person: IPerson = new Person("王大爷"); // 创建IPerson实现类
    console.log(person.say());                 // Hello, I'm 王大爷
    console.log(person.name);                  // 王大爷
    
    person = new Teacher("王老师");             // 创建IPerson实现类
    console.log(person.say());                 // Hello, I'm 王老师
    console.log(person.name);                  // 王老师
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33

# 1.2.7:小结

本节简单介绍了 TS 基础语法部分,掌握这些基础部分可以支撑日常简单应用开发了,对于 TS 的高级部分读者请参考官网 (opens new window)

(adsbygoogle = window.adsbygoogle || []).push({});
请作者喝杯咖啡

津公网安备 12011402001367号

津ICP备2020008934号-2