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 字符串,因为它们可能包含恶意代码。
  • 当需要处理特殊类型(如函数、日期等)时,可以使用自定义的序列化和反序列化方法。
相关推荐
To_OC18 分钟前
LC 17 电话号码的字母组合:我的回溯算法,就是从这道题开窍的
javascript·算法·leetcode
vipbic26 分钟前
中后台越做越乱后,我用插件化把它救回来了
前端·vue.js
Hyyy32 分钟前
Computer Use 适合做什么,不适合做什么——一次真实使用后的思考
前端
小和尚同志1 小时前
前端 AI 单元测试思考与落地
前端·人工智能·aigc
invicinble2 小时前
c端系统,其实更像一个信息展示平台
前端
你怎么知道我是队长2 小时前
JavaScript的变量和数据类型介绍
开发语言·javascript·ecmascript
李姆斯3 小时前
管理是否可以被完全量化
前端·产品经理·团队管理
名字还没想好☜4 小时前
Next.js 中间件实战:鉴权、重定向与 A/B 分流
开发语言·前端·javascript·中间件·react·next.js
广州灵眸科技有限公司4 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) INI文件操作
java·前端·javascript·网络·人工智能
心中有国也有家4 小时前
AtomGit Flutter 鸿蒙客户端:ModalBottomSheet 实战
android·javascript·学习·flutter·华为·harmonyos