ArkTS运行时常见问题
============

#### 正则运算与预期输出结果不一致场景

如果使用正则运算时结果与期望不符，请检查以下场景。

#### \[h2\]正则运算对于\\b处理与预期不一致

let str = '\\u2642';
let res = str.replace(/\\b/g, '/');
console.info('res = ' + res);
// 期望输出: res = ♂
// 实际输出: res = /♂/

规避方案：暂无。

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/79/v3/04Dtfe5MQByGcwxITs1kVg/note_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260612T073250Z&HW-CC-Expire=86400&HW-CC-Sign=3865F0D8179E4D2E2619C1A5BFA4670FE8256F8B64F1794CF9ED82E99883D53A)

正则匹配\\b（单词边界）遇到某些ASCII编码之外的字符时，会将其当成ASCII字符来处理，从而将不是单词边界匹配识别成单词边界。

#### \[h2\]正则运算对于先行断言((?=pattern)或(?!pattern)) 嵌套在后行断言((?<=pattern)或(?<!pattern))内部的场景与预期不一致

console.info(\`res:${'abcdef'.match(/(?<=ab(?=c)cd)ef/)}\`);
// 期望输出: res:ef
// 实际输出: res:null

规避方案：使用/(?<=abcd)ef/代替/(?<=ab(?=c)cd)ef/。

#### \[h2\]正则运算对于大小写的处理与预期不一致

let res = /\\u{10400}/ui.test('\\u{10428}');
console.info('res = ' + res);
// 期望输出: res = true
// 实际输出: res = false

规避方案：暂无。

#### \[h2\]正则运算/()/ug匹配时lastIndex与预期不一致

let L = '\\ud800';
let T = '\\udc00';
let u = /()/ug;
u.lastIndex = 1;
u.exec(L + T + L + T);
console.info('u.lastIndex = ' + u.lastIndex);
// 期望输出: u.lastIndex = 0
// 实际输出: u.lastIndex = 1

规避方案：暂无。

#### \[h2\]正则运算\[\]内部使用'-'与预期不一致

let str = 'a-b';
let reg = /\[+-\\s\]/;
console.info('reg.exec(str) = ' + reg.exec(str));
// 期望输出: reg.exec(str) = -
// 实际输出: reg.exec(str) = null

规避方案：使用转义后的"-"。

let str = 'a-b';
let reg = /\[+\\-\\s\]/;
console.info('reg.exec(str) = ' + reg.exec(str));

#### \[h2\]正则运算具名捕获组获取与预期不一致

let reg = new RegExp('(a)(?<b>b)');
let res = reg.exec('ab');
console.info('JSON.stringify(res?.groups) = ' + JSON.stringify(res?.groups));
// 期望输出: JSON.stringify(res?.groups) = {'b':'b'}
// 实际输出: JSON.stringify(res?.groups) = {'b':'a'}

规避方案：计算具名捕获组位置获取具名捕获组匹配的内容。

let reg = new RegExp('(a)(?<b>b)');
let res = reg.exec('ab') as Array<string>;
console.info('JSON.stringify(res?.groups) = {\\'b\\':' + JSON.stringify(res\[2\]) + '}');

#### \[h2\]正则匹配使用'|'与预期不一致

在使用正则匹配时，如果'|'前是一个空匹配，会导致'|'后的匹配不成功。

let reg = /a(?:|x)$/;
let res = reg.exec('ax');
console.info('JSON.stringify(res) = ' + JSON.stringify(res));
// 期望输出: JSON.stringify(res) = \['ax'\]
// 实际输出: JSON.stringify(res) = null

规避方案：使用reg2或reg3替换reg1。

let reg1 = /a(?:|x)$/;
let reg2 = /a(?:x)?$/;
let reg3 = /a(?:x){0,1}$/;

#### \[h2\]TypedArray.prototype.map触发内联缓存优化后，在回调中将数值number转为浮点数number与期望不一致

for(let i = 0; i < 1000; i++) {} // 触发内联缓存优化

let arr = new Int32Array(\[1, 2, 3, 4, 5\]);
let result = arr.map(val => {
  let res = (Math.pow(val, 1)) \* 100;
  return res;
})

console.info('result\[0\]:', result\[0\]);
// 期望输出: result\[0\]:100
// 实际输出: result\[0\]:104

规避方案：使用Array.from将TypedArray先转换为普通Array，再处理number。

let arr = new Int32Array(\[1, 2, 3, 4, 5\]);

let normalArr = Array.from(arr);
let result = normalArr.map(val => {
  let res = (Math.pow(val, 1)) \* 100;
  return res;
});

console.info('result\[0\]:', result\[0\]);
// 输出: result\[0\]:100

#### \[h2\]Number.parseFloat解析浮点数number类型非规格化数值与期望不一致

parseFloat接口不支持对非规格化数进行解析。当输入字符串表示一个浮点数number类型的非规格化数，一律输出0。

let result = parseFloat('5e-324');
console.info('testcase: ', result);
// 期望输出: testcase: 5e-324
// 实际输出: testcase: 0

规避方案：暂无，开发者应避免使用parseFloat接口对非规格化数进行解析。

#### \[h2\]Set constructor入参为多维数组的解析与期望不一致

const arr1: number\[\] = \[1, 2\];
const arr2: number\[\] = \[3, 4\];
const set = new Set<number\[\]>(\[arr1, arr2\]);
let result = JSON.stringify(Array.from(set));
console.info('res: ', result);
// 期望输出: res: \[\[1,2\],\[3,4\]\]
// 实际输出: res: \[2,4\]

规避方案：暂无，开发者应避免构造set时入参为多维数组。

#### \[h2\]Object.entries处理Uint8Array与Uint16Array数组结果与期望不一致

// TestArray.js
const typedArr = new Uint8Array(\[10, 20, 30\]);
try {
  const result = Object.entries(typedArr);
  console.info('no error throw');
} catch(e) {
  console.info(e);
}
// 期望输出：no error throw
// 实际输出: RangeError: object entries is not supported IsJSUint8Array or IsJSUint16Array

// TestArrayExt.js
const typedArr = new Uint16Array(\[10, 20, 30\]);
try {
   const result = Object.entries(typedArr);
   console.info('no error throw');
} catch (e) {
   console.info(e);
}
// 期望输出：no error throw
// 实际输出: RangeError: object entries is not supported IsJSUint8Array or IsJSUint16Array

规避方案：使用Array.from将TypedArray先转换为普通Array，再使用Object.entries。

// TestArray.js
const typedArr = new Uint8Array(\[10, 20, 30\]);
try {
  const normalArr1 = Array.from(typedArr);
  const result = Object.entries(normalArr1);
  console.info('no error throw');
} catch(e) {
  console.info(e);
}
// 输出：no error throw

#### \[h2\]字符串 replace 接口对于第一个参数为空字符串的场景与预期不一致

在使用字符串replace接口时，如果第一个参数是空字符串，则直接返回原始字符串。

let str = 'dddd';
let res = str.replace('', 'abc');
console.info('res = ' + res);
// 期望输出: res = abcdddd
// 实际输出: res = dddd

规避方案：使用正则表达式 /^/ 表示字符串起始符，作为第一个参数。

let str = 'dddd';
let res = str.replace(/^/, 'abc');

#### Async函数内部异常的处理机制

**场景**

如果在Async函数内部产生了异常，且没有使用catch捕获该异常，在ArkTS中不会导致进程退出。其本质是Async函数返回了一个rejected状态的Promise对象，没有被处理，使得Promise的rejected状态没有被捕获。Async函数内部的异常会变成 unhandledRejection，表现为异常未抛出。

**Async函数内部异常的捕获方式**

1.  使用[errorManager.on()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-app-ability-errormanager#errormanageronerror)捕获到Async函数产生的unhandledrejection事件，再通过编写errorManager.on()注册的回调函数，来进行异常处理操作。
    
    import { errorManager } from '@kit.AbilityKit';
      // ...
      errorManager.on('unhandledRejection', (a:ESObject, b:Promise<ESObject>) => {
        console.info('Async test', a);
        // ...
      })
    
2.  在Async函数内部，针对可能发生异常的代码块添加try-catch逻辑，直接捕获可能出现的异常。
    

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/6/v3/xFAvj-1nT5-ZCO_sbhnrfQ/caution_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260612T073250Z&HW-CC-Expire=86400&HW-CC-Sign=BA94ECB1526E3E914CE2B176594072F96455B413FFF6839F2686BAD431E3E6A4)

注意必须在Async函数内部，外部无法捕获Async函数内部的异常，外部只能通过errorManager.on()监听。

**查看Async函数内部是否有异常的方式**

若开发者仅需要查看Async函数内部是否产生异常，首先需要在DevEco Studio终端执行以下hilog命令开启debug级别日志打印：

   hilog -b D

然后点击DevEco Studio下方HiLog选项卡，输入过滤条件“Throw error:”，即可查看到Async函数内产生的异常信息。

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/18/v3/cSmcHZDWRqigoCuui-KrVg/zh-cn_image_0000002625187039.png?HW-CC-KV=V1&HW-CC-Date=20260612T073250Z&HW-CC-Expire=86400&HW-CC-Sign=19CA56A4990B6AC89B142B3A862702D064237A5AD32D4EF6D42DEC13D01CF21D)

#### Array.flatMap()接口常见问题

Array.flatMap()接口在处理包含Proxy的Array时，未正确展平嵌套的Proxy Array，导致返回结果与预期不一致。

#### \[h2\]ArkTS使用场景

let arr1 = \[0, 1\];
let arr2 = \[2, 3\];
const emptyHandler = {} as ProxyHandler<number\[\]>;
let proxy1 = new Proxy(arr1, emptyHandler);
let proxy2 = new Proxy(arr2, emptyHandler);
let arr3 = \[proxy1, proxy2\];
let res = arr3.flatMap(x => x);

console.info('res length:', res.length.toString());
// 期望输出: res length: 4
// 实际输出: res length: 2
console.info('res\[0\] is: ', res\[0\].toString());
// 期望输出: res\[0\] is: 0
// 实际输出: res\[0\] is: 0,1

#### \[h2\]ArkUI使用场景

ArkUI状态管理框架会为使用状态变量装饰器（如@State、@Trace、@Local）装饰的Array添加一层代理，用于观测API调用产生的变化。如果状态装饰器与Array组合，并且调用Array.flatMap，会出现如下问题。

以状态管理V2为例：

@Entry
@ComponentV2
struct Index {
  @Local p: number\[\] = \[0, 1\];
  @Local q: number\[\] = \[2, 3\];
  c: number\[\]\[\] = \[this.p, this.q\];
  d: number\[\] = \[\];

  aboutToAppear(): void {
    this.d = this.c.flatMap(it => it);
  }

  build() {
    Column() {
      Text(\`${this.d\[0\]}\`); // 预期显示：0; 实际显示：0,1
    }
  }
}

#### \[h2\]Array.flatMap规避方案

避免使用Array.flatMap()接口，改为调用Array.map()接口后再调用深度为1的Array.flat()接口。以上文ArkTS使用场景为例：

// 使用规避方案前
let res = arr3.flatMap(x => x);
// ...
// 使用规避方案后
let res = arr3.map(x => x).flat();

#### \[h2\]Proxy的handler对象中key类型与EcmaScript规范定义不一致

在Proxy对象的handler函数中，对于数字类型的key，ArkTS当前实现是采用保持数字类型不变，但是按照EcmaScript规范，应当转为string类型。

// TestArray.js
{
  let handler = {
    get(target, key) {
      console.info('get', key, typeof key);
      return Reflect.get(target, key);
    },
    set(target, key, value) {
      console.info('set', key, typeof key);
      return Reflect.set(target, key, value);
    },
    deleteProperty(target, key) {
      console.info('delete', key, typeof key);
      return Reflect.deleteProperty(target, key);
    },
    has(target, key) {
      console.info('has', key, typeof key);
      return Reflect.has(target, key);
    }
  }
  let obj = {};
  let px = new Proxy(obj, handler);
  px\[1\];
  // 实际输出：get 1 number
  px\[2\] = 2;
  // 实际输出：set 2 number
  3 in px;
  // 实际输出：has 3 number
  delete px\[2\];
  // 实际输出：delete 2 number
}

规避方案：若业务逻辑依赖于key必须为string类型，可在handler函数内部对数字类型的key进行显式转换。示例如下：

// TestArray.js
{
  let handler = {
    get(target, key) {
      if (typeof key === 'number') {
        key = String(key);
      }
      console.info('get', key, typeof key);
      return Reflect.get(target, key);
    },
    set(target, key, value) {
      if (typeof key === 'number') {
        key = String(key);
      }
      console.info('set', key, typeof key);
      return Reflect.set(target, key, value);
    },
    deleteProperty(target, key) {
      if (typeof key === 'number') {
        key = String(key);
      }
      console.info('delete', key, typeof key);
      return Reflect.deleteProperty(target, key);
    },
    has(target, key) {
      if (typeof key === 'number') {
        key = String(key);
      }
      console.info('has', key, typeof key);
      return Reflect.has(target, key);
    }
  }
  let obj = {};
  let px = new Proxy(obj, handler);
  px\[1\];
  // 实际输出：get 1 string
  px\[2\] = 2;
  // 实际输出：set 2 string
  3 in px;
  // 实际输出：has 3 string
  delete px\[2\];
  // 实际输出：delete 2 string
}

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/c3/v3/9GXCZSoPQx2JEC_QaPHHug/note_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260612T073250Z&HW-CC-Expire=86400&HW-CC-Sign=998DC496AA7D0610DC62DD55270429FDB394E06CB2CB7BCCF31CF7DD48D35120)

上述demo中部分语法，如 "3 in px", "delete px\[2\]", "Reflect.deleteProperty"，在ets文件中不可用。

#### \[h2\]JSON.stringify的replacer函数中数组索引的key类型与EcmaScript规范定义不一致

JSON.stringify的replacer函数中，对于数组索引key的类型，ArkTS当前实现是采用保持数字类型不变，但是按照EcmaScript规范，应当转为string类型。

// TestArray.js
{
  let arr = \[10, 20, 30, 40\];
  function replacer(key, value) {
    if (key === '2') {
        return value \* 2;
    }
    return value;
  }
  console.info(JSON.stringify(arr, replacer));
  // 实际输出：\[10,20,30,40\]
}

规避方案：若业务逻辑依赖于key必须为string类型，可在replacer函数内部对数字类型的key进行显式转换。示例如下：

// TestArray.js
{
  let arr = \[10, 20, 30, 40\];
  function replacer(key, value) {
    if (typeof key === 'number') {
      key = String(key);
    }
    if (key === '2') {
        return value \* 2;
    }
    return value;
  }
  console.info(JSON.stringify(arr, replacer));
  // 实际输出：\[10,20,60,40\]
}