JSON.stringfy、JSON.parse 使用及注意问题

写在前面

平时工作中会大量用到 JSON.stringify、JSON.parse 处理 JSON 数据。因为知道 JSON.parse 在解析的时候如果遇到格式不符的字符串会报错,所以一般会用 try...catch... 函数包裹 JSON.parse,避免抛出错误终止程序执行。JSON.stringify 一般没有做处理,今天在开发过程中遇到 JSON.stringify 处理循环引用的对象,导致程序终止。所以特意总结一下 JSON.stringfy、JSON.parse 使用及注意问题,希望以后在开发工程中避免一些错误问题。

简要介绍

JSON.stringify() 和 JSON.parse() 是 JavaScript 中用于处理 JSON 数据的两个重要方法。

1. JSON.stringify():

  • 介绍:

    • 当处理对象时,该方法会将对象转换为 JSON 字符串。
    • 可以传入第二个参数用于指定替换或过滤属性的回调函数,或者传入一个数组用于指定要序列化的属性列表。
    • 可以传入第三个参数用于指定缩进的空格数,以便获得格式化的输出。
  • 注意事项:

    • 注意循环引用的问题:如果对象存在循环引用,即对象中的某个属性引用了自身或引用了对象链中的其他对象,JSON.stringify() 会抛出异常。

2. JSON.parse():

  • 介绍:

    • 该方法用于将 JSON 字符串解析为 JavaScript 对象。
    • 可以传入第二个参数用于自定义解析器,允许更灵活地处理数据。
  • 注意事项:

    • 如果传入的字符串无效或不是有效的 JSON 格式,JSON.parse() 会抛出异常。
    • 如果 JSON 字符串中包含函数、正则表达式或日期等特殊类型,解析后的结果将失去相应的特殊类型,而被转换为字符串。

JSON.stringify 使用及注意问题

只传一个参数

javascript 复制代码
const obj = { 
  name: "lin", 
  age: 18, 
  city: "Beijing" 
};
const jsonString1 = JSON.stringify(obj);
console.log(jsonString1); // '{"name":"John","age":30,"city":"New York"}'

传入第二个参数

(1)传入一个数组来指定要序列化的属性列表

使用第二个参数传入一个数组来指定要序列化的属性列表:

javascript 复制代码
obj = {
  name: 'lin',
  age: 18,
  city: 'Beijing'
};

// 指定要序列化的属性列表
let jsonString = JSON.stringify(obj, ['name', 'age']);

console.log(jsonString); // 输出结果: {"name":"lin","age":18}

传入一个数组 ['name', 'age'] 作为第二个参数,指定了要序列化的属性列表。最终得到的 jsonString 只包含了指定的属性 "name" 和 "age",而 "city" 属性被排除在外。

(2)传入一个函数实现更复杂的属性控制

使用 JSON.stringify 的第二个参数 keyFilter 来指定替换或过滤属性的回调函数。这个回调函数可以帮助你控制 JSON 序列化的过程,从而避免循环引用问题。举个简单的例子:

javascript 复制代码
circularObj = {};
circularObj.circularKey = circularObj;

const keyFilter = (key, value) => {
  if (key === 'circularKey') {
    return 'Circular Reference Detected!';
  }
  return value;
};

const jsonString = JSON.stringify(circularObj, keyFilter);
console.log(jsonString);

在这个例子中,我们定义了一个包含循环引用的对象 circularObj,并使用 keyFilter 函数来检测并替换循环引用属性。这样就可以避免循环引用问题导致的 JSON 序列化失败。

(3)传入第三个参数指定缩进的空格数

javascript 复制代码
const obj = { 
  name: "lin", 
  age: 18, 
  city: "Beijing" 
};
const jsonString1 = JSON.stringify(obj);
console.log(jsonString1); // '{"name":"John","age":30,"city":"New York"}'
const jsonString2 = JSON.stringify(obj, null, 2);
console.log(jsonString2); // '{\n  "name": "John",\n  "age": 30,\n  "city": "New York"\n}'

注意循环引用问题

循环引用示例

下面是一个简单的循环引用的例子:

javascript 复制代码
// 创建一个循环引用的对象
let obj = {};
obj.prop = obj;

// 尝试序列化这个对象
let jsonString = JSON.stringify(obj);

// 尝试解析这个字符串
let parsedObj = JSON.parse(jsonString);

console.log(parsedObj); // 在此处会抛出异常,因为 JSON 格式不支持循环引用

JSON 格式不支持循环引用。因此,在使用 JSON.stringify() 和 JSON.parse() 时,需要确保要序列化的对象中不存在循环引用的情况。

如何解决循环引用问题

如果无法某一个对象就是需要循环引用,在处理的时候可以使用 JSON.stringify 的第二个参数来指定替换或过滤属性的回调函数。在回调函数里可以控制 JSON 序列化的过程,从而避免循环引用问题。举个例子:

javascript 复制代码
circularObj = {};
circularObj.circularKey = circularObj;

const keyFilter = (key, value) => {
  if (key === 'circularKey') {
    return 'Circular Reference Detected!';
  }
  return value;
};

const jsonString = JSON.stringify(circularObj, keyFilter);
console.log(jsonString); // {"circularKey":"Circular key Detected!"}

在这个例子中,定义了一个包含循环引用的对象 circularObj,并使用 keyFilter 函数来检测并替换循环引用属性。这样就可以避免循环引用问题导致的 JSON 序列化失败。

JSON.parse 使用及注意问题

传入第二个参数用于自定义解析器

这样可以更灵活地处理数据

javascript 复制代码
const jsonStr = '{"name": "lin", "age": 18, "isStudent": false, "date": "2024-03-05"}';

const changeDate = (key, value) => {
  if (key === 'date') {
    // 将日期字符串转换为 Date 对象
    return new Date(value);
  }
  return value;
};

const parsedData = JSON.parse(jsonStr, changeDate);

console.log(parsedData);

注意问题

传入的字符串无效或不是有效的 JSON 格式

这种情况下, JSON.parse() 方法会抛出异常。

javascript 复制代码
const invalidJsonStr = '{name: "lin", age: 18}';

try {
  const parsedData = JSON.parse(invalidJsonStr);
  console.log(parsedData);
} catch (error) {
  // Error parsing JSON: Expected property name or '}' in JSON at position 1 (line 1 column 2)
  console.error('Error parsing JSON: ' + error.message);
}

在这个例子中,我们定义的字符串没有用双引号包裹属性名。当我们尝试使用 JSON.parse() 解析这个无效的 JSON 字符串时,会抛出异常。通过 try...catch 块,我们可以捕获并处理这个异常,避免程序终止。

字符串中包含函数、正则表达式或日期等特殊类型

这种情况下,解析后的结果将失去相应的特殊类型,而被转换为字符串。因为 JSON 格式本身只能表示基本数据类型,无法直接表示这些特殊类型。示例:

javascript 复制代码
const data = {
  name: 'lin',
  func: function() {
    console.log('Hello!');
  },
  regex: /hello/,
  date: new Date()
};

const jsonString = JSON.stringify(data);
console.log('JSON String:', jsonString);

const parsedData = JSON.parse(jsonString);
console.log('Parsed Data:', parsedData);

如果需要保留这些特殊类型,可以采取其他方式进行处理,比如自定义序列化和反序列化方法。

小结

使用 JSON.stringify 和 JSON.parse 要注意以下问题:

  • 在使用 JSON.stringify() 时,确保要序列化的对象是可序列化的,即不包含循环引用和特殊类型(如函数)。
  • 当使用 JSON.stringify() 进行对象序列化时,确保对象的属性值不包含循环引用,否则会导致无限递归并抛出异常。
  • 在使用 JSON.parse() 时,确保要解析的字符串是有效的 JSON 格式,否则会抛出异常。
  • 考虑到安全性,避免解析不受信任的 JSON 字符串,因为它们可能包含恶意代码。
  • 当需要处理特殊类型(如函数、日期等)时,可以使用自定义的序列化和反序列化方法。
相关推荐
m0_748247551 小时前
Web 应用项目开发全流程解析与实战经验分享
开发语言·前端·php
m0_748255022 小时前
前端常用算法集合
前端·算法
真的很上进2 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
web130933203982 小时前
vue elementUI form组件动态添加el-form-item并且动态添加rules必填项校验方法
前端·vue.js·elementui
NiNg_1_2343 小时前
Echarts连接数据库,实时绘制图表详解
前端·数据库·echarts
如若1233 小时前
对文件内的文件名生成目录,方便查阅
java·前端·python
滚雪球~4 小时前
npm error code ETIMEDOUT
前端·npm·node.js
沙漏无语4 小时前
npm : 无法加载文件 D:\Nodejs\node_global\npm.ps1,因为在此系统上禁止运行脚本
前端·npm·node.js
supermapsupport4 小时前
iClient3D for Cesium在Vue中快速实现场景卷帘
前端·vue.js·3d·cesium·supermap
brrdg_sefg4 小时前
WEB 漏洞 - 文件包含漏洞深度解析
前端·网络·安全