管理中心
我的

JSON扩展库

场景介绍

该库扩展了原生JSON功能,提供了额外的错误处理、循环引用检测、BigInt处理以及对不同输入类型的严格检查。代码中底层依赖于原生JSON.parse和JSON.stringify,但在此基础上加入了多种自定义逻辑并提供额外的has和remove接口,具体可见@arkts.json。

JSON扩展库主要适用于以下场景:

  • 需要处理BigInt的JSON解析或序列化。

  • 需要更严格的参数校验和错误处理。

  • 需要在序列化对象时检测循环引用。

  • 需要安全的对象操作(has/remove)。

该库适用于需要增强JSON功能的场景,特别是在处理BigInt和严格的参数校验时。

JSON扩展说明

parse

parse(text: string, reviver?: Transformer, options?: ParseOptions): Object | null

解析JSON字符串,支持BigInt模式。

与原生的区别:

展开
特性 原生parse 本库parse
BigInt支持 不支持(抛出TypeError) 支持(通过parseBigInt扩展)
参数校验 弱校验 强校验(抛出BusinessError)
错误信息 原生错误(如SyntaxError) 自定义BusinessError
reviver参数 支持 支持,但强制类型检查

stringify

stringify(value: Object, replacer?: (number | string)[] | null, space?: string | number): string

stringify(value: Object, replacer?: Transformer, space?: string | number): string

将对象转换为JSON字符串,支持BigInt模式。

与原生的区别:

展开
特性 原生stringify 本库stringify
BigInt支持 不支持(抛出TypeError) 支持(通过stringifyBigInt扩展)
循环引用检测 抛出TypeError 检测并抛出BusinessError
参数校验 弱校验 强校验(replacer必须是函数或数组)
错误信息 原生错误 自定义BusinessError

has

has(obj: object, property: string): boolean

检查对象是否包含指定的属性,确保传入的值是一个对象,并且属性键是有效的字符串。

与原生的区别:

展开
特性 原生方式(obj.hasOwnProperty) 本库has
参数校验 无校验(可能误用) 强制检查obj是普通对象,property是非空字符串
错误处理 可能静默失败 抛出BusinessError

remove

remove(obj: object, property: string): void

从对象中删除指定的属性。

展开
特性 原生方式(delete obj.key) 本库remove
参数校验 无校验(可能误删) 强制检查obj是普通对象,property是非空字符串
错误处理 可能静默失败 抛出BusinessError

总结

展开
功能 原生JSON 本库
严格参数校验 不支持 支持
循环引用检测 不支持 支持
BigInt处理 不支持 支持
增强的错误处理(BusinessError) 不支持 支持
额外方法(has/remove) 不支持 支持

开发场景

解析包含嵌套引号的JSON字符串场景

JSON字符串中的嵌套引号会破坏其结构,将导致解析失败。

// 比如以下JSON字符串,由于嵌套引号导致结构破坏,执行JSON.parse将会抛异常。
// let jsonStr = `{"info": "{"name": "zhangsan", "age": 18}"}`;

以下提供两种方式解决该场景问题:

方式1:避免出现嵌套引号的操作。

import { JSON } from '@kit.ArkTS';

interface Info {
  name: string;
  age: number;
}

interface TestObj {
  info: Info;
}

interface TestStr {
  info: string;
}
  // ...
  /*
   * 将原始JSON字符串`{"info": "{"name": "zhangsan", "age": 18}"}`
   * 修改为`{"info": {"name": "zhangsan", "age": 18}}`。
   * */
  let jsonStr = `{"info": {"name": "zhangsan", "age": 18}}`;
  let obj1  = JSON.parse(jsonStr) as TestObj;
  console.info(JSON.stringify(obj1));    // {"info":{"name":"zhangsan","age":18}}
  // 获取JSON字符串中的name信息
  console.info(obj1.info.name); // zhangsan

方式2:将JSON字符串中嵌套的引号进行双重转义,恢复JSON的正常结构。

import { JSON } from '@kit.ArkTS';

interface Info {
  name: string;
  age: number;
}

interface TestObj {
  info: Info;
}

interface TestStr {
  info: string;
}
  // ...
  /*
   * 将原始JSON字符串`{"info": "{"name": "zhangsan", "age": 18}"}`进行双重转义
   * 修改为`{"info": "{\\"name\\": \\"zhangsan\\", \\"age\\": 18}"}`
   * */
  let jsonStr = `{"info": "{\\"name\\": \\"zhangsan\\", \\"age\\": 18}"}`;
  let obj2 = JSON.parse(jsonStr) as TestStr;
  console.info(JSON.stringify(obj2));    // {"info":"{\"name\": \"zhangsan\", \"age\": 18}"}
  // 获取JSON字符串中的name信息
  let obj3 = JSON.parse(obj2.info) as Info;
  console.info(obj3.name); // zhangsan

解析包含大整数的JSON字符串场景

当JSON字符串中存在小于-(2^53-1)或大于(2^53-1)的整数时,解析后数据会出现精度丢失或不正确的情况。该解析场景需要指定BigIntMode,将大整数解析为BigInt。

import { JSON } from '@kit.ArkTS';
  // ...
  let numberText = '{"number": 10, "largeNumber": 112233445566778899}';

  let numberObj1 = JSON.parse(numberText) as Object;
  console.info((numberObj1 as object)?.['largeNumber']);    // 112233445566778900

  // 使用PARSE_AS_BIGINT的BigInt模式进行解析,避免出现大整数解析错误
  let options: JSON.ParseOptions = {
    bigIntMode: JSON.BigIntMode.PARSE_AS_BIGINT,
  }

  let numberObj2 = JSON.parse(numberText, null, options) as Object;

  console.info(typeof (numberObj2 as object)?.['number']);   // number
  console.info((numberObj2 as object)?.['number']);    // 10

  console.info(typeof (numberObj2 as object)?.['largeNumber']);    // bigint
  console.info((numberObj2 as object)?.['largeNumber']);    // 112233445566778899

序列化BigInt对象场景

为弥补原生JSON无法序列化BigInt对象的缺陷,本库提供以下两种JSON序列化方式:

方式1:不使用自定义转换函数,直接序列化BigInt对象。

import { JSON } from '@kit.ArkTS';
// ...
  let bigIntObject = BigInt(112233445566778899n)

  console.info(JSON.stringify(bigIntObject)); // 112233445566778899

方式2:使用自定义转换函数,需预处理BigInt对象进行序列化操作。

import { JSON } from '@kit.ArkTS';
// ...
  let bigIntObject = BigInt(112233445566778899n)

  // 错误序列化用法:自定义函数中直接返回BigInt对象
  // 错误案例:JSON.stringify(bigIntObject, (key: string, value: Object): Object =>{ return value; });

  // 正确序列化用法:自定义函数中将BigInt对象预处理为string对象
  let result: string = JSON.stringify(bigIntObject, (key: string, value: Object): Object => {
    if (typeof value === 'bigint') {
      return value.toString();
    }
    return value;
  });
  console.info('result:', result); // result: "112233445566778899"

序列化浮点数number场景

在JSON序列化中,浮点数处理存在一个特殊行为:当小数部分为零时,为保持数值的简洁表示,序列化结果会自动省略小数部分。这可能导致精度信息丢失,影响需要精确表示浮点数的场景(如金融金额、科学计量)。以下示例提供解决该场景的方法:

import { JSON } from '@kit.ArkTS';
  // ...
  // 序列化小数部分不为零的浮点数,可以正常序列化
  let floatNumber1 = 10.12345;
  console.info(JSON.stringify(floatNumber1)); // 10.12345

  // 序列化小数部分为零的浮点数,为保持数值的简洁表示,会丢失小数部分的精度
  let floatNumber2 = 10.00;
  console.info(JSON.stringify(floatNumber2)); // 10

  // 以下是防止浮点数精度丢失的方法:
  let result = JSON.stringify(floatNumber2, (key: string, value: Object): Object => {
    if (typeof value === 'number') {
      // 按照业务场景需要,定制所需的固定精度
      return value.toFixed(2);
    }
    return value;
  });
  console.info(result); // "10.00"