JSON 解析与序列化

JSON解析与序列化

掌握JSON数据与编程语言对象之间的转换方法

JSON解析与序列化概述

什么是JSON解析与序列化?

JSON解析与序列化是处理JSON数据的两个核心过程,它们实现了JSON字符串与编程语言对象之间的相互转换。

JS
JavaScript对象

编程语言中的数据结构

S
序列化

对象 → JSON字符串

JSON
JSON字符串

数据交换格式

P
解析

JSON字符串 → 对象

JS
JavaScript对象

编程语言中的数据结构

JSON解析

将JSON字符串转换为编程语言对象的过程。

  • 验证JSON格式的正确性
  • 将JSON数据结构映射到语言特定对象
  • 处理数据类型转换
  • JavaScript: JSON.parse()
JSON序列化

将编程语言对象转换为JSON字符串的过程。

  • 将对象属性转换为键值对
  • 处理循环引用和特殊数据类型
  • 格式化输出以提高可读性
  • JavaScript: JSON.stringify()

JSON解析

JavaScript中的JSON解析
JSON.parse(text[, reviver])

JSON.parse() 方法将JSON字符串解析为JavaScript对象。

基本用法
// JSON字符串
const jsonString = '{"name": "张三", "age": 30, "isStudent": false}';

// 解析为JavaScript对象
const obj = JSON.parse(jsonString);

console.log(obj.name);      // "张三"
console.log(obj.age);       // 30
console.log(obj.isStudent); // false
reviver函数

reviver函数可以在解析过程中对结果进行转换。

使用reviver函数
const jsonString = '{"name": "张三", "age": 30, "birthDate": "1990-05-15"}';

const obj = JSON.parse(jsonString, function(key, value) {
    // 将日期字符串转换为Date对象
    if (key === 'birthDate') {
        return new Date(value);
    }
    // 将年龄转换为字符串
    if (key === 'age') {
        return value + '岁';
    }
    return value;
});

console.log(obj.birthDate); // Date对象
console.log(obj.age);       // "30岁"
错误处理

解析无效的JSON字符串会抛出异常,需要使用try-catch处理。

错误处理示例
function safeParse(jsonString) {
    try {
        return JSON.parse(jsonString);
    } catch (error) {
        console.error('JSON解析错误:', error.message);
        return null;
    }
}

// 有效的JSON
const validResult = safeParse('{"name": "张三"}');
console.log(validResult); // {name: "张三"}

// 无效的JSON
const invalidResult = safeParse('{name: "张三"}'); // 缺少引号
console.log(invalidResult); // null
常见解析错误
  • 语法错误 - JSON格式不正确(如缺少引号、逗号等)
  • 数据类型错误 - 使用了JSON不支持的数据类型(如undefined、函数等)
  • 编码问题 - 字符编码不一致导致解析失败

JSON序列化

JavaScript中的JSON序列化
JSON.stringify(value[, replacer[, space]])

JSON.stringify() 方法将JavaScript值转换为JSON字符串。

基本用法
// JavaScript对象
const obj = {
    name: "张三",
    age: 30,
    isStudent: false,
    hobbies: ["阅读", "游泳"]
};

// 序列化为JSON字符串
const jsonString = JSON.stringify(obj);

console.log(jsonString);
// '{"name":"张三","age":30,"isStudent":false,"hobbies":["阅读","游泳"]}'
replacer参数

replacer可以是一个函数或数组,用于控制序列化过程中哪些属性被包含在结果中。

使用replacer函数
const obj = {
    name: "张三",
    age: 30,
    password: "secret123",
    isAdmin: true
};

// 使用replacer函数过滤属性
const jsonString = JSON.stringify(obj, function(key, value) {
    // 排除密码字段
    if (key === 'password') {
        return undefined;
    }
    return value;
});

console.log(jsonString);
// '{"name":"张三","age":30,"isAdmin":true}'
使用replacer数组
const obj = {
    name: "张三",
    age: 30,
    email: "zhangsan@example.com",
    phone: "13800138000"
};

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

console.log(jsonString);
// '{"name":"张三","age":30}'
space参数

space参数用于控制输出字符串的缩进,提高可读性。

使用space参数格式化输出
const obj = {
    name: "张三",
    age: 30,
    address: {
        city: "北京",
        country: "中国"
    }
};

// 不缩进
console.log(JSON.stringify(obj));
// '{"name":"张三","age":30,"address":{"city":"北京","country":"中国"}}'

// 缩进2个空格
console.log(JSON.stringify(obj, null, 2));
// {
//   "name": "张三",
//   "age": 30,
//   "address": {
//     "city": "北京",
//     "country": "中国"
//   }
// }

// 使用制表符缩进
console.log(JSON.stringify(obj, null, '\t'));
// {
//   "name": "张三",
//   "age": 30,
//   "address": {
//     "city": "北京",
//     "country": "中国"
//   }
// }
序列化规则

JSON.stringify()在序列化时会遵循特定规则:

  • 原始值 - 直接转换为对应的JSON值
  • 对象 - 枚举自身可枚举属性
  • 数组 - 保留元素顺序
  • undefined、函数、Symbol - 在对象中转换为null,在数组中转换为null
  • Date对象 - 转换为ISO格式的字符串
  • 循环引用 - 抛出错误

高级技巧

自定义序列化 - toJSON方法

对象可以定义toJSON方法来自定义序列化行为。

实现toJSON方法
class User {
    constructor(name, age, email) {
        this.name = name;
        this.age = age;
        this.email = email;
        this.createdAt = new Date();
    }

    // 自定义序列化
    toJSON() {
        return {
            name: this.name,
            age: this.age,
            email: this.email,
            createdAt: this.createdAt.toISOString().split('T')[0] // 只保留日期部分
        };
    }
}

const user = new User("李四", 25, "lisi@example.com");
const jsonString = JSON.stringify(user);

console.log(jsonString);
// '{"name":"李四","age":25,"email":"lisi@example.com","createdAt":"2023-10-05"}'
处理循环引用

当对象存在循环引用时,JSON.stringify会抛出错误。可以使用自定义replacer函数处理。

处理循环引用
// 创建循环引用
const obj = { name: "循环引用示例" };
obj.self = obj; // 循环引用

// 自定义replacer处理循环引用
function circularReplacer() {
    const seen = new WeakSet();
    return function(key, value) {
        if (typeof value === 'object' && value !== null) {
            if (seen.has(value)) {
                return '[Circular]';
            }
            seen.add(value);
        }
        return value;
    };
}

const jsonString = JSON.stringify(obj, circularReplacer());
console.log(jsonString);
// '{"name":"循环引用示例","self":"[Circular]"}'
性能优化

对于大型对象的序列化,可以考虑以下优化策略:

  • 只序列化需要的属性
  • 避免深度嵌套的对象结构
  • 对于频繁序列化的对象,缓存序列化结果
  • 使用流式处理大型数据集
选择性序列化
const largeObject = {
    // ... 大量数据
    id: 123,
    name: "大型对象",
    metadata: { /* 大量元数据 */ },
    content: { /* 大量内容数据 */ }
};

// 只序列化需要的字段
function serializeSummary(obj) {
    return JSON.stringify({
        id: obj.id,
        name: obj.name
        // 不包含metadata和content
    });
}

const summary = serializeSummary(largeObject);
console.log(summary); // '{"id":123,"name":"大型对象"}'

多语言实现

不同编程语言中的JSON处理
Python
import json

# JSON解析
json_string = '{"name": "张三", "age": 30}'
python_dict = json.loads(json_string)
print(python_dict["name"])  # 张三

# JSON序列化
python_obj = {"name": "李四", "age": 25}
json_string = json.dumps(python_obj, ensure_ascii=False)
print(json_string)  # {"name": "李四", "age": 25}

# 美化输出
pretty_json = json.dumps(python_obj, indent=2, ensure_ascii=False)
print(pretty_json)
Java
import com.fasterxml.jackson.databind.ObjectMapper;

// JSON解析
String jsonString = "{\"name\":\"张三\",\"age\":30}";
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> map = mapper.readValue(jsonString, Map.class);
System.out.println(map.get("name")); // 张三

// JSON序列化
Map<String, Object> obj = new HashMap<>();
obj.put("name", "李四");
obj.put("age", 25);
String json = mapper.writeValueAsString(obj);
System.out.println(json); // {"name":"李四","age":25}

// 美化输出
String prettyJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
System.out.println(prettyJson);
C#
using System.Text.Json;

// JSON解析
string jsonString = "{\"name\":\"张三\",\"age\":30}";
var obj = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonString);
Console.WriteLine(obj["name"]); // 张三

// JSON序列化
var data = new { name = "李四", age = 25 };
string json = JsonSerializer.Serialize(data);
Console.WriteLine(json); // {"name":"李四","age":25}

// 美化输出
var options = new JsonSerializerOptions { WriteIndented = true };
string prettyJson = JsonSerializer.Serialize(data, options);
Console.WriteLine(prettyJson);
语言特性对比
语言 解析方法 序列化方法 主要库
JavaScript JSON.parse() JSON.stringify() 内置
Python json.loads() json.dumps() json (标准库)
Java ObjectMapper.readValue() ObjectMapper.writeValueAsString() Jackson, Gson
C# JsonSerializer.Deserialize() JsonSerializer.Serialize() System.Text.Json
PHP json_decode() json_encode() 内置
Ruby JSON.parse() JSON.generate() json (标准库)

交互式演示

JSON解析与序列化演示
JavaScript对象
JSON字符串
高级选项

最佳实践

JSON解析与序列化最佳实践
解析最佳实践
  • 始终使用try-catch处理解析错误
  • 验证JSON数据的完整性和格式
  • 使用reviver函数处理特殊数据类型
  • 对来自不可信源的JSON数据进行验证
  • 考虑使用JSON Schema验证数据结构
  • 处理大型JSON数据时使用流式解析
序列化最佳实践
  • 只序列化需要的属性,减少数据量
  • 使用replacer函数过滤敏感信息
  • 为调试目的使用格式化输出
  • 生产环境使用紧凑格式减少带宽
  • 处理循环引用避免序列化错误
  • 为自定义对象实现toJSON方法
安全注意事项
  • 避免解析来自不可信源的JSON数据,防止代码注入
  • 在处理用户提供的JSON时,验证数据结构和内容
  • 考虑使用沙箱环境处理不受信任的JSON
  • 对敏感信息进行适当的过滤和脱敏
性能优化建议
  • 对于频繁操作的对象,缓存序列化结果
  • 使用对象池减少内存分配
  • 对于大型数据集,考虑分页或增量处理
  • 在可能的情况下,使用二进制格式替代JSON