本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

一、JSON扩展库

1. 概念

  • JSON扩展库扩展了原生JSON功能,提供增强的错误处理、循环引用检测、BigInt处理等功能

  • 底层依赖于原生JSON.parse和JSON.stringify,但加入了多种自定义逻辑

  • 提供额外的has和remove接口,增强对象操作安全性

2. 适用场景

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

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

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

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

二、核心功能对比

1. parse方法

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

2. stringify方法

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

3. has方法

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

4. remove方法

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

三、功能总结

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

四、代码示例

1. 导入模块

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

2. 解析包含嵌套引号的JSON字符串

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

方案1:避免嵌套引号

interface UserProfile {
  userName: string;
  userAge: number;
}

interface ResponseData {
  profile: UserProfile;
}

// 原始有问题的JSON:`{"profile": "{"userName": "李四", "userAge": 25}"}`
// 修改为正确的JSON结构
const validJsonStr = `{"profile": {"userName": "李四", "userAge": 25}}`;

const parsedData = JSON.parse(validJsonStr) as ResponseData;
console.info(JSON.stringify(parsedData)); // {"profile":{"userName":"李四","userAge":25}}
console.info(parsedData.profile.userName); // 李四

方案2:双重转义嵌套引号

interface UserProfile {
  userName: string;
  userAge: number;
}

interface StringResponse {
  profile: string;
}

// 对嵌套引号进行双重转义
const escapedJsonStr = `{"profile": "{\\"userName\\": \\"王五\\", \\"userAge\\": 30}"}`;

const stringData = JSON.parse(escapedJsonStr) as StringResponse;
console.info(JSON.stringify(stringData)); // {"profile":"{\"userName\": \"王五\", \"userAge\": 30}"}

// 解析嵌套的JSON字符串
const nestedData = JSON.parse(stringData.profile) as UserProfile;
console.info(nestedData.userName); // 王五

3. 解析包含大整数的JSON字符串

问题:
当JSON字符串中存在超过JavaScript安全整数范围(±(2^53-1))的整数时,解析后会出现精度丢失。

方案:使用BigInt模式解析

const bigNumberJson = '{"smallNumber": 42, "hugeNumber": 987654321098765432}';

// 原生解析 - 大整数精度丢失
const nativeResult = JSON.parse(bigNumberJson) as Record<string, any>;
console.info(nativeResult.hugeNumber); // 987654321098765400 (精度丢失)

// 扩展库解析 - 使用BigInt模式
const parseOptions: JSON.ParseOptions = {
  bigIntMode: JSON.BigIntMode.PARSE_AS_BIGINT,
};

const extendedResult = JSON.parse(bigNumberJson, null, parseOptions) as Record<string, any>;
console.info(typeof extendedResult.smallNumber); // number
console.info(extendedResult.smallNumber); // 42
console.info(typeof extendedResult.hugeNumber); // bigint
console.info(extendedResult.hugeNumber); // 987654321098765432n (精确值)

4. 序列化BigInt对象

方案1:直接序列化

const largeId = BigInt('1234567890123456789');
console.info(JSON.stringify(largeId)); // "1234567890123456789"

方案2:使用自定义转换函数

const accountData = {
  accountId: BigInt('112233445566778899'),
  accountName: '企业账户',
  balance: BigInt('999999999999999999')
};

// 错误用法:自定义函数中直接返回BigInt对象
// JSON.stringify(accountData, (key, value) => value);

// 正确用法:将BigInt转换为字符串
const serializedData = JSON.stringify(accountData, (key: string, value: any): any => {
  if (typeof value === 'bigint') {
    return value.toString() + 'n'; // 添加'n'后缀标识BigInt
  }
  return value;
});

console.info("序列化结果:", serializedData); 
// {"accountId":"112233445566778899n","accountName":"企业账户","balance":"999999999999999999n"}

5. 序列化浮点数保持精度

问题:
JSON序列化时,小数部分为零的浮点数会自动省略小数部分,导致精度信息丢失。

方案:使用自定义转换函数固定精度

// 正常序列化 - 小数部分不为零
const preciseNumber = 15.6789;
console.info(JSON.stringify(preciseNumber)); // 15.6789

// 问题序列化 - 小数部分为零,精度丢失
const wholeNumber = 20.00;
console.info(JSON.stringify(wholeNumber)); // 20

// 解决方案:使用replacer函数保持精度
const financialData = {
  price: 99.00,
  taxRate: 0.08,
  discount: 15.50
};

const preciseJson = JSON.stringify(financialData, (key: string, value: any): any => {
  if (typeof value === 'number') {
    // 根据业务需求设置固定精度
    return Number(value.toFixed(2));
  }
  return value;
});

console.info(preciseJson); // {"price":99.00,"taxRate":0.08,"discount":15.50}

6. 安全的对象操作

使用has方法安全检查属性

const employeeRecord = {
  employeeId: 'E1001',
  employeeName: '张工程师',
  department: '研发部'
};

// 原生方式 - 可能存在误用风险
// console.info(employeeRecord.hasOwnProperty('employeeName')); // true

// 扩展库方式 - 安全检查
try {
  const hasName = JSON.has(employeeRecord, 'employeeName');
  console.info(`是否存在employeeName属性: ${hasName}`); // true
  
  const hasSalary = JSON.has(employeeRecord, 'salary');
  console.info(`是否存在salary属性: ${hasSalary}`); // false
} catch (error) {
  console.error('属性检查失败:', error);
}

使用remove方法安全删除属性

const productInfo = {
  productId: 'P2001',
  productName: '智能手机',
  price: 2999,
  category: '电子产品'
};

console.info('删除前:', JSON.stringify(productInfo)); 
// {"productId":"P2001","productName":"智能手机","price":2999,"category":"电子产品"}

// 扩展库方式 - 安全删除
try {
  JSON.remove(productInfo, 'category');
  console.info('删除后:', JSON.stringify(productInfo)); 
  // {"productId":"P2001","productName":"智能手机","price":2999}
} catch (error) {
  console.error('属性删除失败:', error);
}

五、ParseOptions配置

BigIntMode选项

  • PARSE_AS_BIGINT: 将大整数解析为BigInt类型

  • PARSE_AS_NUMBER: 将大整数解析为Number类型(可能精度丢失)

const options: JSON.ParseOptions = {
  bigIntMode: JSON.BigIntMode.PARSE_AS_BIGINT,
};

六、总结

1. 数据类型处理

  • 金融数据使用固定精度序列化

  • 大整数使用BigInt模式解析

  • 敏感数据在序列化前进行脱敏处理

2. 错误处理

  • 始终使用try-catch包裹JSON操作

  • 利用扩展库的强校验避免运行时错误

   JSON扩展库提供了比原生JSON更强大、更安全的功能,特别是在BigInt处理、严格参数校验和错误处理方面。通过增强的parse、stringify方法以及新增的has、remove方法,可以更安全、更精确地处理JSON数据。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐