Back to Blog
2026-02-24ToolBox Team

JSON 处理最佳实践 - 从解析到验证

📌 相关工具推荐 | Related Tool

🕸️tools.jsonVisualizer
jsondatabest-practicesjavascript

JSON 处理最佳实践

JSON(JavaScript Object Notation)已成为现代 Web 数据交互的通用格式。API 返回 JSON,前后端都用 JSON 通信,配置文件也用 JSON。掌握 JSON 处理的最佳实践,对提升代码质量至关重要。

1. JSON 格式化与验证

为什么需要格式化?

从 API 获得的 JSON 通常都是"压缩"形式,看起来像一团乱麻:

{"users":[{"id":1,"name":"Alice","email":"alice@example.com","roles":["admin","editor"]},{"id":2,"name":"Bob","roles":["viewer"]}]}

格式化后变得易读:

{
  "users": [
    {
      "id": 1,
      "name": "Alice",
      "email": "alice@example.com",
      "roles": ["admin", "editor"]
    },
    {
      "id": 2,
      "name": "Bob",
      "roles": ["viewer"]
    }
  ]
}

我们的 JSON Visualizer 可以将原始 JSON 美化,同时通过树形和图形视图帮助理解复杂的数据结构。

手工格式化 JSON

const rawJson = '{"name":"Alice","age":30}';

// 格式化
const formatted = JSON.stringify(JSON.parse(rawJson), null, 2);
console.log(formatted);

// 输出:
// {
//   "name": "Alice",
//   "age": 30
// }

参数说明:

  • 第一个参数:要序列化的对象
  • 第二个参数:null 表示不过滤任何属性(可以是函数或数组)
  • 第三个参数:缩进空格数(2 或 4 最常用)

2. JSON 验证和解析错误处理

常见解析错误

// ❌ 错误:单引号不符合 JSON 标准
JSON.parse("{'name': 'Alice'}");  // SyntaxError

// ❌ 错误:末尾有逗号
JSON.parse('{"name": "Alice",}');  // SyntaxError

// ❌ 错误:使用了 JavaScript 的 undefined
JSON.parse('{"value": undefined}');  // SyntaxError

// ✅ 正确
JSON.parse('{"name": "Alice"}');  // OK

安全的解析方法

function safeJsonParse(jsonString, defaultValue = null) {
  try {
    return JSON.parse(jsonString);
  } catch (error) {
    console.error('JSON 解析失败:', error.message);
    return defaultValue;
  }
}

// 使用
const data = safeJsonParse(someString, {});

使用 Schema 验证

Zod 是一个流行的 TypeScript-first 数据验证库:

import { z } from 'zod';

// 定义 Schema
const UserSchema = z.object({
  id: z.number(),
  name: z.string().min(1).max(100),
  email: z.string().email(),
  age: z.number().int().min(0).max(150).optional(),
  roles: z.array(z.enum(['admin', 'editor', 'viewer'])),
  createdAt: z.string().datetime()
});

// 验证数据
try {
  const validData = UserSchema.parse({
    id: 1,
    name: 'Alice',
    email: 'alice@example.com',
    roles: ['admin'],
    createdAt: '2026-02-27T10:00:00Z'
  });
  console.log('✓ 数据有效');
} catch (error) {
  console.error('✗ 验证失败:', error.issues);
}

3. 大型 JSON 数据处理

流式处理

处理超大 JSON 文件(如 1GB+ 的数据导出)时,不能一次性加载到内存。

import JSONStream from 'JSONStream';
import fs from 'fs';

fs.createReadStream('huge-file.json')
  .pipe(JSONStream.parse('users.*'))  // 解析 users 数组的每个元素
  .on('data', (user) => {
    // 逐条处理,而非一次加载
    console.log(user.id, user.name);
  })
  .on('error', (err) => {
    console.error('流处理错误:', err);
  });

使用生成器避免内存溢出

function* jsonGenerator(jsonArray) {
  for (const item of jsonArray) {
    yield item;
  }
}

const users = JSON.parse(fs.readFileSync('users.json'));
for (const user of jsonGenerator(users)) {
  processUser(user);  // 逐条处理
}

4. JSON 转换和映射

对象结构转换

// 原始数据
const users = [
  { id: 1, firstName: 'Alice', lastName: 'Smith', email: 'alice@example.com' },
  { id: 2, firstName: 'Bob', lastName: 'Johnson', email: 'bob@example.com' }
];

// 需要转换为简化格式
const transformed = users.map(user => ({
  id: user.id,
  fullName: `${user.firstName} ${user.lastName}`,
  email: user.email
}));

/* 结果:
[
  { id: 1, fullName: "Alice Smith", email: "alice@example.com" },
  { id: 2, fullName: "Bob Johnson", email: "bob@example.com" }
]
*/

嵌套对象展平

// 深层嵌套的对象
const nested = {
  user: {
    profile: {
      name: 'Alice',
      contact: {
        email: 'alice@example.com',
        phone: '123-456-7890'
      }
    }
  }
};

// 展平为一层
function flatten(obj, prefix = '') {
  let result = {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      const newKey = prefix ? `${prefix}.${key}` : key;
      if (typeof obj[key] === 'object' && obj[key] !== null) {
        Object.assign(result, flatten(obj[key], newKey));
      } else {
        result[newKey] = obj[key];
      }
    }
  }
  return result;
}

const flattened = flatten(nested);
/* 结果:
{
  "user.profile.name": "Alice",
  "user.profile.contact.email": "alice@example.com",
  "user.profile.contact.phone": "123-456-7890"
}
*/

5. JSON 与 CSV 转换

API 通常返回 JSON,但分析团队需要 CSV 导出到 Excel。

function jsonToCsv(jsonArray) {
  if (!jsonArray || jsonArray.length === 0) return '';

  // 获取所有字段作为表头
  const headers = Object.keys(jsonArray[0]);
  
  // CSV 第一行是表头
  const csv = [headers.join(',')];
  
  // 转换每一行数据,处理特殊字符
  for (const item of jsonArray) {
    const row = headers.map(header => {
      const value = item[header];
      if (value === null || value === undefined) return '';
      // 如果包含逗号或引号,需要用双引号包围和转义
      if (typeof value === 'string' && (value.includes(',') || value.includes('"'))) {
        return `"${value.replace(/"/g, '""')}"`;
      }
      return value;
    });
    csv.push(row.join(','));
  }

  return csv.join('\n');
}

// 使用示例
const data = [
  { id: 1, name: 'Alice', email: 'alice@example.com' },
  { id: 2, name: 'Bob, Jr.', email: 'bob@example.com' }
];

const csvString = jsonToCsv(data);
console.log(csvString);
/* 输出:
id,name,email
1,Alice,alice@example.com
2,"Bob, Jr.",bob@example.com
*/

反向转换,CSV 转 JSON:

function csvToJson(csvString) {
  const lines = csvString.trim().split('\n');
  const headers = lines[0].split(',').map(h => h.trim());
  
  return lines.slice(1).map(line => {
    // 简单版本,不处理引号中的逗号
    const values = line.split(',').map(v => v.trim());
    const obj = {};
    headers.forEach((header, index) => {
      obj[header] = values[index];
    });
    return obj;
  });
}

6. 性能优化

选择合适的序列化库

对于小型 JSON,JSON.stringify() 足够。但超大数据量时:

// 标准库,但速度较慢
JSON.stringify(largeObject);

// 高性能序列化库
import { stringify } from 'flatted';

const stringified = stringify(largeObject);

压缩 JSON

当通过网络传输 JSON 时,启用 Gzip 压缩:

import zlib from 'zlib';

const data = { /* 大对象 */ };
const jsonString = JSON.stringify(data);

// 压缩
zlib.gzip(jsonString, (err, compressed) => {
  // compressed 就是可以发送的数据
  console.log(`原大小: ${jsonString.length}B`);
  console.log(`压缩后: ${compressed.length}B`);
});

实际场景中,现代框架和服务器(如 Express、Nginx)会自动处理 Gzip。

常见数据转换场景

数据聚合

const orders = [
  { customerId: 1, amount: 100 },
  { customerId: 1, amount: 50 },
  { customerId: 2, amount: 200 }
];

const aggregated = orders.reduce((acc, order) => {
  acc[order.customerId] = (acc[order.customerId] || 0) + order.amount;
  return acc;
}, {});
// { 1: 150, 2: 200 }

字段重命名

const response = [
  { user_id: 1, user_name: 'Alice', user_email: 'alice@example.com' }
];

const renamed = response.map(item => ({
  userId: item.user_id,
  userName: item.user_name,
  userEmail: item.user_email
}));

相关工具推荐