鸿蒙中ArkTs常见问题(三)

68 阅读5分钟

问题1:如何在ArkTS中实现运行时注解的能力

可以使用TS三方库reflect-metadata获得类似java运行时注解的功能。参考reflect-metadata

reflect-metadata提供的装饰器允许对类和属性和方法做标记,并提供了接口可以在运行时获取标记的信息。

import "reflect-metadata"; 

// 三方包的能力暴露在Reflect中 
@Reflect.metadata("TargetClass", 'classData') 
// 标记类,key是"TargetClass", 数据是classData 
class MyClass { 
  @Reflect.metadata("TargetMethod", 'methodData') 
  // 标记方法,key是"TargetMethod", 数据是methodData 
  myMethod() { 
  } 

  @Reflect.metadata("Static", 'staticData') 
  static invoke() { 
  } 
} 

// 运行时获取标记信息 
console.info(Reflect.getMetadata("TargetClass", MyClass)); //classData 
console.info(Reflect.getMetadata("TargetMethod", new MyClass(), "myMethod")); //methodData 
console.info(Reflect.getMetadata("Static", MyClass, "invoke")); // staticData

问题2:如何将Map转换为JSON字符串

可以将Map转成Record后,再通过JSON.stringify()转为JSON字符串。示例如下:

let mapSource = new Map<string, string>(); 
mapSource.set('name', 'name1'); 
mapSource.set('width', '100'); 
mapSource.set('height', '50'); 
 
let jsonObject: Record<string, Object> = {}; 
mapSource.forEach((value, key) => { 
  if (key !== undefined && value !== undefined) { 
    jsonObject[key] = value; 
  } 
}) 
let jsonInfo: string = JSON.stringify(jsonObject); 
console.log('jsonInfo:', jsonInfo); 
// jsonInfo: {"name":"name1","width":"100","height":"50"} 

问题3:如何获取对象的类名

可以先获取类的实例,然后通过constructor的name属性获取类名。

class TestClass { 
  a: string = 'A'; 
  b: string = 'B'; 
} 
 
let testClassObj: TestClass = new TestClass(); 
console.log('TestClass Name:', testClassObj.constructor.name); 

问题4:如何删除Record中的元素

ets限制delete的使用,可以在ts文件中定义工具函数,并在ets中引入使用。

在ts中定义工具函数ObjectUtil:

export class ObjectUtil {
  static DeleteRecord(source: Record<any, any>, key: any): Record<any, any> {
    delete source[key];
    return source;
  }
}

在ets中使用ObjectUtil:

import { ObjectUtil } from './utils';


let recordInfo: Record<string, string> = {
  'key1': 'value1',
  'key2': 'value2',
  'key3': 'value3',
};


@Entry
@Component
struct Index {
  build() {
    Row() {
      Column() {
        Button('delete Record')
          .onClick(() => {
            recordInfo = ObjectUtil.DeleteRecord(recordInfo, 'key1');
            console.log('recordInfo:', JSON.stringify(recordInfo)); // recordInfo: {"key2":"value2","key3":"value3"}
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

问题4:如何将JSON对象转换成HashMap

import { HashMap } from '@kit.ArkTS'; 
 
let str: string = '{\"common_params\": {' + 
  '\"city_id\": 1,' + 
  '\"nav_id_list\": \"\",' + 
  '\"show_hook_card\": 2,' + 
  '\"use_one_stop_structure\": 1,' + 
  '\"version_tag\": \"homepageonestop\"' + 
  '}' + 
  '}'; 
 
let jsonObj: Object = JSON.parse(str); 
let commObj = (jsonObj as Record<string, Object>); 
let commRecord = (commObj['common_params'] as Record<string, Object>); 
let keyStr = Object.keys(commRecord); 
 
for (let index: number = 0; index < keyStr.length; index++) { 
  commRecord[keyStr[index].toString()].toString(); 
} 
 
let hashMapData: HashMap<string, Object> = new HashMap(); 
hashMapData.set('common_params', commRecord); 
 
// common_params: {"city_id":1,"nav_id_list":"","show_hook_card":2,"use_one_stop_structure":1,"version_tag":"homepageonestop"} 
console.log('common_params:', JSON.stringify(hashMapData.get('common_params'))); 

问题5:如何将ArrayBuffer转成string

可以通过util.TextDecoder.create()方法创建一个工具类,再通过decodeToString()方法进行转化。

let decoder = util.TextDecoder.create('utf-8'); 
let str = decoder.decodeToString(new Uint8Array(arrayBuffer));

如将proArrayBuffer返回的ArrayBuffer类型的数据arrayBufferVal转为string:

import { util, buffer } from '@kit.ArkTS'; 

let blobValue: buffer.Blob = new buffer.Blob(['name', 'age', 'sex']); 
let proArrayBuffer = blobValue.arrayBuffer(); 

proArrayBuffer.then((arrayBufferVal: ArrayBuffer) => { 
  let decoder = util.TextDecoder.create('utf-8'); 
  let stringData = decoder.decodeToString(new Uint8Array(arrayBufferVal)); 
  console.log('stringData:', stringData); 
});

问题6:Uint8Array类型和String以及hex如何互相转换

Uint8Array类型和String以及hex实现互相转换,可参考如下代码:

import { buffer, util } from '@kit.ArkTS';

// 字符串转成字节流
function stringToUint8Array(str: string) {
  console.info('字符串转成字节流:' + new Uint8Array(buffer.from(str, 'utf-8').buffer));
  return new Uint8Array(buffer.from(str, 'utf-8').buffer);
}

// 字节流转成可理解的字符串
function uint8ArrayToString(array: Uint8Array) {
  let textDecoderOptions: util.TextDecoderOptions = {
    fatal: false,
    ignoreBOM: true
  }
  let decodeToStringOptions: util.DecodeToStringOptions = {
    stream: false
  }
  let textDecoder = util.TextDecoder.create('utf-8', textDecoderOptions);
  let retStr = textDecoder.decodeToString(array, decodeToStringOptions);
  console.info('字节流转成可理解的字符串:' + retStr);
  return retStr;
}

//十六进制转Uint8Array
function HexStrTouint8Array(data: string): Uint8Array {
  console.info('十六进制转Uint8Array:' + new Uint8Array(buffer.from(data, 'hex').buffer));
  return new Uint8Array(buffer.from(data, 'hex').buffer);
}

// Uint8Array转十六进制
function uint8ArrayToHexStr(data: Uint8Array): string {
  let hexString = '';
  let i: number;
  for (i = 0; i < data.length; i++) {
    let char = ('00' + data[i].toString(16)).slice(-2);
    hexString += char;
  }
  console.info('Uint8Array转十六进制:' + hexString);
  return hexString;
}

let uint8Array: Uint8Array;

@Entry
@Component
struct TypeConversion {
  build() {
    Column({ space: 12 }) {
      Button('字符串转成字节流')
        .onClick(() => {
          let str = 'hello';
          uint8Array = stringToUint8Array(str);
        })
      Button('字节流转字符串')
        .onClick(() => {
          if (uint8Array) {
            uint8ArrayToString(uint8Array);
          }
        })
      Button('十六进制转Uint8Array')
        .onClick(() => {
          let data = '05160b22';
          HexStrTouint8Array(data);
        })
      Button('Uint8Array转十六进制')
        .onClick(() => {
          let uint8Array = new Uint8Array([5, 22, 11, 34]);
          uint8ArrayToHexStr(uint8Array);
        })
    }
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}

问题7:如何进行base64编码

可使用util中的Base64Helper()方法进行base64编码,参考代码如下:

let base64 = new util.Base64Helper(); 
let arr = new Uint8Array([48, 49, 2, 1, 1, 4, 32, 115, 56]); 
let base64Str = base64.encodeToStringSync(arr); // Uint8Array转base64 
console.log('encodeToStringSync',base64Str); 
// base64.decodeSync(''); // base64转Uint8Array 
// console.log('decodeSync',base64.decodeSync('')); 

问题8:如何实现深/浅拷贝

浅拷贝实现方法:

通过ts封装Object.assign()或者使用三方库lodash的_.clone方法。封装Object.assign()示例如下:

ts封装Object.assign():

export class ObjectUtil {
  static Assign<T extends {}, U>(target: T, source: U): T & U {
    return Object.assign(target, source);
  }
}

ets文件中使用封装的ObjectUtil:

import { ObjectUtil } from './utils';

interface InnerStudent {
  age: number,
  score: number
}

interface Student {
  name: string,
  data: InnerStudent
}

let obj1: Student = { name: 'obj1', data: { age: 24, score: 100 } };
let obj2 = ObjectUtil.Assign({}, obj1);
obj2.name = 'obj2';
obj2.data.age = 12;
obj2.data.score = 50;

console.log('obj1:', JSON.stringify(obj1)); // obj1: {"name":"obj1","data":{"age":12,"score":50}}
console.log('obj2:', JSON.stringify(obj2)); // obj2: {"name":"obj2","data":{"age":12,"score":50}}

深拷贝实现方法:

  1. JSON.parse(JSON.stringify()),对于undefined等无法序列化的数据会丢失。
  2. 三方库lodash的_.cloneDeep方法。
  3. 手写递归方法:
// ts中封装工具函数
export function deepCopy(obj: ESObject): ESObject {
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }
  let copy: ESObject;
  if (Array.isArray(obj)) {
    copy = [];
    for (let i = 0; i < obj.length; i++) {
      copy[i] = deepCopy(obj[i]);
    }
  } else {
    copy = {};
    for (let i = 0; i < obj.length(); i++) {
      let key: ESObject = obj[i];
      if (obj.hasOwnProperty(key)) {
        copy[key] = deepCopy(obj[key]);
      }
    }
  }
  return copy;
}

问题9:ArkTS是否支持多继承

接口支持多继承,类不支持,只支持单继承。示例如下:

class TestClassA { 
  address: string = ''; 
} 

class TestClassB { 
  name: string = ''; 
} 

class TestClassC extends TestClassA, TestClassB { // 报错:Classes can only extend a single class. 
} 

interface AreaSize { 
  calculateAreaSize(): number; 
} 

interface Cal { 
  Sub(a: number, b: number): number; 
} 

interface Area extends AreaSize, Cal { 
  areaName: string; 
  length: number; 
  width: number; 
}

问题10:如何使用Record

构造一个对象类型,其属性键为 "Keys" ,其属性值为 "Type",可用于将一种类型的属性映射到另一种类型。示例如下:

interface RecordType { 
  age: number; 
  name: string; 
} 
 
type RecordName = string; 
 
let name1: RecordType = { name: 'name1', age: 5 }; 
let name2: RecordType = { name: 'name2', age: 10 }; 
let name3: RecordType = { name: 'name3', age: 15 }; 
 
let dataInfo: Record<RecordName, RecordType> = { 
  'data1': name1, 
  'data2': name2, 
  'data3': name3, 
}; 

// dataInfo: {"data1":{"name":"name1","age":5},"data2":{"name":"name2","age":10},"data3":{"name":"name3","age":15}} 
console.log('dataInfo:', JSON.stringify(dataInfo));