1# JSON扩展库 2<!--Kit: ArkTS--> 3<!--Subsystem: CommonLibrary--> 4<!--Owner: @xliu-huanwei; @shilei123; @huanghello--> 5<!--Designer: @yuanyao14--> 6<!--Tester: @kirl75; @zsw_zhushiwei--> 7<!--Adviser: @ge-yafang--> 8 9## 场景介绍 10 11该库扩展了原生JSON功能,提供了额外的错误处理、循环引用检测、BigInt处理以及对不同输入类型的严格检查。代码中底层依赖于原生JSON.parse和JSON.stringify,但在此基础上加入了多种自定义逻辑并提供额外的has和remove接口,具体可见[@arkts.json](../reference/apis-arkts/js-apis-json.md)。 12 13JSON扩展库主要适用于以下场景: 14 15- 需要处理BigInt的JSON解析或序列化。 16 17- 需要更严格的参数校验和错误处理。 18 19- 需要在序列化对象时检测循环引用。 20 21- 需要安全的对象操作(has/remove)。 22 23该库适用于需要增强JSON功能的场景,特别是在处理BigInt和严格的参数校验时。 24 25## JSON扩展说明 26 27### parse 28 29parse(text: string, reviver?: Transformer, options?: ParseOptions): Object | null 30 31解析JSON字符串,支持BigInt模式。 32 33**与原生的区别:** 34 35| 特性 | 原生parse | 本库parse | 36| -------- | -------- | -------- | 37| BigInt支持 | 不支持(抛出TypeError) |支持(通过parseBigInt扩展)| 38| 参数校验 | 弱校验 |强校验(抛出BusinessError) | 39| 错误信息 | 原生错误(如SyntaxError) | 自定义BusinessError | 40| reviver参数 | 支持 | 支持,但强制类型检查 | 41 42### stringify 43 44stringify(value: Object, replacer?: (number | string)[] | null, space?: string | number): string 45 46将对象转换为JSON字符串,支持BigInt模式。 47 48**与原生的区别:** 49 50| 特性 | 原生stringify | 本库stringify | 51| -------- | -------- | -------- | 52| BigInt支持 | 不支持(抛出TypeError)| 支持(通过stringifyBigInt扩展) | 53| 循环引用检测 | 抛出TypeError | 检测并抛出BusinessError | 54| 参数校验 | 弱校验 | 强校验(replacer 必须是函数或数组) | 55| 错误信息 | 原生错误 | 自定义BusinessError | 56 57### has 58 59has(obj: object, property: string): boolean 60 61检查对象是否包含指定的属性,确保传入的值是一个对象,并且属性键是有效的字符串。 62 63**与原生的区别:** 64 65| 特性| 原生方式(obj.hasOwnProperty) | 本库has | 66| -------- | -------- | -------- | 67| 参数校验 | 无校验(可能误用) | 强制检查obj是普通对象,property是非空字符串 | 68| 错误处理 | 可能静默失败 | 抛出BusinessError | 69 70### remove 71 72remove(obj: object, property: string): void 73 74从对象中删除指定的属性。 75 76| 特性 | 原生方式(delete obj.key) | 本库remove | 77| -------- | -------- | -------- | 78| 参数校验 | 无校验(可能误删) | 强制检查obj是普通对象,property是非空字符串 | 79| 错误处理 | 可能静默失败 | 抛出BusinessError | 80 81### 总结 82 83| 功能 | 原生JSON | 本库 | 84| ----- | ----- | -----| 85| 严格参数校验 | 不支持 | 支持 | 86| 循环引用检测 | 不支持 | 支持 | 87| BigInt处理 | 不支持 | 支持 | 88| 增强的错误处理(BusinessError) | 不支持 | 支持 | 89| 额外方法(has/remove) | 不支持 | 支持 | 90 91## 开发场景 92 93### 解析包含嵌套引号的JSON字符串场景 94 95JSON字符串中的嵌套引号会破坏其结构,将导致解析失败。 96 97```ts 98// 比如以下JSON字符串,由于嵌套引号导致结构破坏,执行JSON.parse将会抛异常。 99// let jsonStr = `{"info": "{"name": "zhangsan", "age": 18}"}`; 100``` 101 102以下提供两种方式解决该场景问题: 103 104方式1:避免出现嵌套引号的操作。 105 106```ts 107import { JSON } from '@kit.ArkTS'; 108 109interface Info { 110 name: string; 111 age: number; 112} 113 114interface TestObj { 115 info: Info; 116} 117 118interface TestStr { 119 info: string; 120} 121 122/* 123 * 将原始JSON字符串`{"info": "{"name": "zhangsan", "age": 18}"}` 124 * 修改为`{"info": {"name": "zhangsan", "age": 18}}`。 125 * */ 126let jsonStr = `{"info": {"name": "zhangsan", "age": 18}}`; 127let obj1 = JSON.parse(jsonStr) as TestObj; 128console.info(JSON.stringify(obj1)); //{"info":{"name":"zhangsan","age":18}} 129// 获取JSON字符串中的name信息 130console.info(obj1.info.name); // zhangsan 131``` 132 133方式2:将JSON字符串中嵌套的引号进行双重转义,恢复JSON的正常结构。 134 135```ts 136import { JSON } from '@kit.ArkTS'; 137 138interface Info { 139 name: string; 140 age: number; 141} 142 143interface TestObj { 144 info: Info; 145} 146 147interface TestStr { 148 info: string; 149} 150 151/* 152 * 将原始JSON字符串`{"info": "{"name": "zhangsan", "age": 18}"}`进行双重转义, 153 * 修改为`{"info": "{\\"name\\": \\"zhangsan\\", \\"age\\": 18}"}`。 154 * */ 155let jsonStr = `{"info": "{\\"name\\": \\"zhangsan\\", \\"age\\": 18}"}`; 156let obj2 = JSON.parse(jsonStr) as TestStr; 157console.info(JSON.stringify(obj2)); // {"info":"{\"name\": \"zhangsan\", \"age\": 18}"} 158// 获取JSON字符串中的name信息 159let obj3 = JSON.parse(obj2.info) as Info; 160console.info(obj3.name); // zhangsan 161``` 162 163### 解析包含大整数的JSON字符串场景 164 165当JSON字符串中存在小于-(2^53-1)或大于(2^53-1)的整数时,解析后数据会出现精度丢失或不正确的情况。该解析场景需要指定BigIntMode,将大整数解析为BigInt。 166 167```ts 168import { JSON } from '@kit.ArkTS'; 169 170let numberText = '{"number": 10, "largeNumber": 112233445566778899}'; 171 172let numberObj1 = JSON.parse(numberText) as Object; 173console.info((numberObj1 as object)?.["largeNumber"]); // 112233445566778900 174 175// 使用PARSE_AS_BIGINT的BigInt模式进行解析,避免出现大整数解析错误。 176let options: JSON.ParseOptions = { 177 bigIntMode: JSON.BigIntMode.PARSE_AS_BIGINT, 178} 179 180let numberObj2 = JSON.parse(numberText, null, options) as Object; 181 182console.info(typeof (numberObj2 as object)?.["number"]); // number 183console.info((numberObj2 as object)?.["number"]); // 10 184 185console.info(typeof (numberObj2 as object)?.["largeNumber"]); // bigint 186console.info((numberObj2 as object)?.["largeNumber"]); // 112233445566778899 187``` 188 189### 序列化BigInt对象场景 190 191为弥补原生JSON无法序列化BigInt对象的缺陷,本库提供以下两种JSON序列化方式: 192 193方式1:不使用自定义转换函数,直接序列化BigInt对象。 194 195```ts 196import { JSON } from '@kit.ArkTS'; 197 198let bigIntObject = BigInt(112233445566778899n) 199 200console.info(JSON.stringify(bigIntObject)); // 112233445566778899 201``` 202 203方式2:使用自定义转换函数,需预处理BigInt对象进行序列化操作。 204 205```ts 206import { JSON } from '@kit.ArkTS'; 207 208let bigIntObject = BigInt(112233445566778899n) 209 210// 错误序列化用法:自定义函数中直接返回BigInt对象 211// JSON.stringify(bigIntObject, (key: string, value: Object): Object =>{ return value; }); 212 213// 正确序列化用法:自定义函数中将BigInt对象预处理为string对象 214let result: string = JSON.stringify(bigIntObject, (key: string, value: Object): Object => { 215 if (typeof value === 'bigint') { 216 return value.toString(); 217 } 218 return value; 219}); 220console.info("result:", result); // result: "112233445566778899" 221``` 222 223### 序列化浮点数number场景 224 225在JSON序列化中,浮点数处理存在一个特殊行为:当小数部分为零时,为保持数值的简洁表示,序列化结果会自动省略小数部分。这可能导致精度信息丢失,影响需要精确表示浮点数的场景(如金融金额、科学计量)。以下示例提供解决该场景的方法: 226 227```ts 228import { JSON } from '@kit.ArkTS'; 229 230// 序列化小数部分不为零的浮点数,可以正常序列化。 231let floatNumber1 = 10.12345; 232console.info(JSON.stringify(floatNumber1)); // 10.12345 233 234// 序列化小数部分为零的浮点数,为保持数值的简洁表示,会丢失小数部分的精度。 235let floatNumber2 = 10.00; 236console.info(JSON.stringify(floatNumber2)); // 10 237 238// 以下是防止浮点数精度丢失的方法: 239let result = JSON.stringify(floatNumber2, (key: string, value: Object): Object => { 240 if (typeof value === 'number') { 241 // 按照业务场景需要,定制所需的固定精度。 242 return value.toFixed(2); 243 } 244 return value; 245}); 246console.info(result); // "10.00" 247``` 248