• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.parseJSON.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