开天辟地 HarmonyOS(鸿蒙) - ArkTS 基础: 数据类型

源码 https://github.com/webabcd/HarmonyDemo
作者 webabcd

开天辟地 HarmonyOS(鸿蒙) - ArkTS 基础: 数据类型

示例如下:

pages\arkts\basic\DataType.ets

import { TitleBar, MyLog } from '../../TitleBar';

@Entry
@Component
struct DataTypeDemo {
  build() {
    Column() {
      TitleBar()
      Text("代码示例结合 HiLog 日志一起看")
    }
  }
}


// let 声明的变量是块作用域,仅块内可用,声明必须初始化
{
  let a = 10;
  MyLog.d(`${a}`); // 10
}

// const 常量,块作用域,一旦声明必须初始化,之后不允许修改
{
  const b = 10;
  MyLog.d(`${b}`); // 10
}

{
  // 基本数据类型 boolean, number, string
  let a: boolean = true;
  let b: number = 10;
  let c: string = "abc";

  // 对象数据类型,即通过 new 出来的对象
  let e: Date = new Date();

  // 定义为 Object 类型,则可以赋值为任意基本类型或任意对象(不可以赋值为 null 和 undefined)
  let f1: Object = new Date();
  // 定义为 object 类型,则可以赋值为任意对象(不可以赋值为基本数据类型,以及 null 和 undefined)
  let f2: object = new Date();

  // 注:ArkTS 不支持 typescript 的 any 和 unknown

  // 非要用 any 的话可以使用 ESObject(注:ESObject 是 any 的别名)
  let x: ESObject = new Date();
  MyLog.d(`${x.getTime()}`); // 1743665460665
}

{
  // 在 undefined 和 null 做比较时,== 会做类型转换,=== 不会做类型转换
  MyLog.d(`${undefined == null}, ${undefined === null}`); // true, false
  MyLog.d(`${typeof null == 'object'}, ${typeof undefined == 'undefined'}`); // true, true
  MyLog.d(`${Number(null)}, ${Number(undefined)}`); // 0, NaN
  MyLog.d(`${Boolean(null)}, ${Boolean(undefined)}`); // false, false
}

{
  // 定义变量的时候如果没有指定数据类型,但是赋值了,则 ArkTS 会自动推导出变量的数据类型
  let a = 10;
  MyLog.d(`${typeof a}`); // number

  let b = new Date()

  // 通过 typeof 判断数据类型,可以判断基本类型
  MyLog.d(`${typeof a == 'number'}`); // true

  // 通过 typeof 判断数据类型,如果是对象类型,则获取到的一律是 object,无法获取到具体的对象类型
  MyLog.d(`${typeof b == 'object'}`); // true

  // 通过 typeof 也可以判断是否是 function
  MyLog.d(`${typeof b.getDate == 'function'}`); // true

  // 如果是对象类型,则需要通过 instanceof 判断具体的对象类型
  MyLog.d(`${b instanceof Date}`); // true

  // 通过 Array.isArray() 判断是否是数组类型
  MyLog.d(`${Array.isArray([1, 2, 3])}`); // true

  // 通过 every() 判断数组中的元素是否均为指定的类型
  MyLog.d(`${[1, 2, 3].every(item => typeof item === 'number')}`); // true
}

{
  // 联合类型,可以定义变量为多个数据类型中的一个
  let a: number | string;
  a = 10;
  MyLog.d(typeof a); // number
  a = "abc";
  MyLog.d(typeof a); // string

  // 函数的参数和返回值之类的都可以使用联合类型
  let fun1 = (x: number | string): number | string | void => {
    if (typeof x == 'number') {
      return x * 2;
    } else if (typeof x == 'string') {
      return `hello ${x}`;
    } else {
      // void
    }
  }
  MyLog.d(`${fun1(100)}, ${fun1("webabcd")}`); // 200, hello webabcd

  let b: number | undefined;
  if (Math.random() > 0.5) {
    b = 10;
  } else {
    b = undefined
  }
  // 注:如果运行时才能确定变量的具体类型,且函数参数的支持类型并不能覆盖变量的所有可能的类型时,则调用函数时必须要先判断传入变量的类型,否则会编译时报错
  if (typeof b == 'number') {
    MyLog.d(`${fun1(b)}`); // 20
  }
}

{
  // 注:请注意区分类似如下的情况
  // 比如 new Number() 和 Number(), 前者是是一个类的构造函数用于实例化对象,后者是全局函数返回的是一个基本类型
  let a = new Number("10");
  let b = Number("10");
  MyLog.d(`${typeof a}, ${typeof b}`); // object, number
}

{
  // 通过 interface 声明一个自定义的数据类型
  interface MyInterface {
    key: string;
    value: string;
  }
  let a: MyInterface = {key: "key", value: "value"};
  MyLog.d(`${a.key}, ${a.value}`); // key, value
}

{
  // 支持隐式转换
  let a: number = 100;
  let b = a + "abc" // 100abc
  MyLog.d(b);

  // if 会将 0, "", null, undefined, NaN 隐式地转换为布尔值 false
  if (!0 && !"" && !null && !undefined && !NaN) {
    MyLog.d("if 条件的隐式转换");
  }
}

// 鸭子类型(duck typing)
{
  class Class1 {
    title: string = "";
  }
  class Class2 {
    title: string;
    constructor(title: string) {
      this.title = title
    }
  }

  let f1 = (p: Class1): string => {
    return p.title;
  }
  // 通过 as 断言绕过编译时的类型检查,两个虽然没有任何关系但是形状相同的对象,也是可以正常转换的
  let r1 = f1(new Class2("abc") as Class1)
  MyLog.d(r1) // abc

  let f2 = (p: Array<Class1>): string => {
    return p.map(x => x.title).join(',');
  }
  // 支持鸭子类型(duck typing)的概念,即如果它走起来像鸭子,叫起来也像鸭子,那我们就可以认为它是鸭子
  // 本例传递的是 Class2 数组,但是函数参数需要的是 Class1 数组, 因为 Class1 和 Class2 的形状相同,依据 duck typing 这种场景是可以正常转换的
  let r2 = f2([new Class2("a"), new Class2("b"), new Class2("c")])
  MyLog.d(r2) // a,b,c

  // 依据 duck typing 支持形状相同的匿名 interface 到指定 class 的转换
  let r3 = f1({ title: "abc" })
  MyLog.d(r3) // abc


  interface IPerson {
    name: string
  }
  let f3 = (p: IPerson): string => {
    return p.name
  }
  // 依据 duck typing 支持形状相同的匿名 interface 到指定 interface 的转换
  let r4 = f3({ name: "abc" })
  MyLog.d(r4) // abc
}

{
  // 通过 type 指定类型别名
  type Name = string;
  type NameMethod = () => string;
  type NameOrMethod = Name | NameMethod;
  let f1 = (p: NameOrMethod): Name => {
    if (typeof p == 'string') {
      return p;
    } else if (typeof p == 'function') {
      return p();
    }
    return "不可能";
  }
  MyLog.d(f1("webabcd")); // webabcd
  MyLog.d(f1(() => "webabcd")); // webabcd


  // 通过 type 指定类型别名(允许将具体的值作为类型)
  type MyType = "webabcd" | 44;
  // 传参时只允许传入 "webabcd" 或 44
  let f2 = (p: MyType): string => {
    return `${p}`;
  }
  MyLog.d(f2("webabcd")); // webabcd
  MyLog.d(f2(44)); // 44


  // 通过 type 指定类型别名(支持匿名类型)
  type MyCallback = (name: string, age: number) => string;
  let f3 = (callback: MyCallback): void => {
    let result = callback("webabcd", 44)
    MyLog.d(result) // webabcd, 44
  }
  f3((name, age) => {
    return `${name}, ${age}`
  })
}

{
  class Animal {
    public name: string;
    constructor(name: string) {
      this.name = name;
    }
  }
  class Dog extends Animal {
    hello() {
      MyLog.d("hello dog");
    }
  }

  let f1 = (animal: Animal) => {
    // 通过 instanceof 判断一个基类对象是否是某个子类对象
    if (animal instanceof Dog) {
      // 通过 as 将基类对象转换为子类对象
      let dog = animal as Dog;
      dog.hello(); // hello dog
    }
  }
  f1(new Dog("dog"));
}

{
  class Person {
    public name: string;
    constructor(name: string) {
      this.name = name;
    }
  }

  // 引用类型
  let person = new Person("abc")
  let f1 = (p: Person) => {
    p.name = "xyz" // 修改的是 person 的 name, 此时 p 的引用和 person 的引用是相同的
    p = new Person("zzz") // 修改了 p 的引用,此后 p 的引用和 person 的引用不同了
  }
  f1(person)
  MyLog.d(person.name) // xyz

  // 引用类型
  let a = [1, 2, 3]
  let f2 = (arr: number[]) => {
    arr[0] = 100 // 修改的是 a 的第一个元素, 此时 a 的引用和 arr 的引用是相同的
    arr = [7, 8, 9] // 修改了 arr 的引用,此后 a 的引用和 arr 的引用不同了
  }
  f2(a)
  MyLog.d(a.toString()) // 100,2,3

  // 值类型
  let b = '123'
  let f3 = (str: string) => {
    str = '789' // str 是 b 的副本
  }
  f3(b)
  MyLog.d(b) // 123
}

源码 https://github.com/webabcd/HarmonyDemo
作者 webabcd

posted @ 2025-02-05 13:24  webabcd  阅读(124)  评论(0)    收藏  举报