鸿蒙中 JSON库处理BigInt、浮点数
本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
一、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数据。
更多推荐


所有评论(0)