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 字符串,因为它们可能包含恶意代码。
  • 当需要处理特殊类型(如函数、日期等)时,可以使用自定义的序列化和反序列化方法。
相关推荐
她似晚风般温柔78912 分钟前
Uniapp + Vue3 + Vite +Uview + Pinia 分商家实现购物车功能(最新附源码保姆级)
开发语言·javascript·uni-app
Jiaberrr1 小时前
前端实战:使用JS和Canvas实现运算图形验证码(uniapp、微信小程序同样可用)
前端·javascript·vue.js·微信小程序·uni-app
everyStudy2 小时前
JS中判断字符串中是否包含指定字符
开发语言·前端·javascript
城南云小白2 小时前
web基础+http协议+httpd详细配置
前端·网络协议·http
前端小趴菜、2 小时前
Web Worker 简单使用
前端
web_learning_3212 小时前
信息收集常用指令
前端·搜索引擎
Ylucius2 小时前
动态语言? 静态语言? ------区别何在?java,js,c,c++,python分给是静态or动态语言?
java·c语言·javascript·c++·python·学习
tabzzz2 小时前
Webpack 概念速通:从入门到掌握构建工具的精髓
前端·webpack
200不是二百2 小时前
Vuex详解
前端·javascript·vue.js
滔滔不绝tao2 小时前
自动化测试常用函数
前端·css·html5