问题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}}
深拷贝实现方法:
- JSON.parse(JSON.stringify()),对于undefined等无法序列化的数据会丢失。
- 三方库lodash的_.cloneDeep方法。
- 手写递归方法:
// 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));