JSON 基础

JSON 的语法规则、数据类型和常用方法

问题

什么是 JSON?它的语法规则是什么?如何在 JavaScript 中使用?

解答

什么是 JSON

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,也易于机器解析和生成。

语法规则

{
  "name": "张三",
  "age": 25,
  "isStudent": false,
  "hobbies": ["读书", "游泳"],
  "address": {
    "city": "北京",
    "street": "朝阳路"
  },
  "spouse": null
}

JSON 支持的数据类型:

  • 字符串:必须用双引号
  • 数字:整数或浮点数
  • 布尔值truefalse
  • null:空值
  • 数组:有序列表
  • 对象:键值对集合

JavaScript 中的 JSON 方法

// JSON.stringify() - 将对象转为 JSON 字符串
const obj = {
  name: '张三',
  age: 25,
  hobbies: ['读书', '游泳']
};

const jsonStr = JSON.stringify(obj);
console.log(jsonStr);
// {"name":"张三","age":25,"hobbies":["读书","游泳"]}

// 格式化输出,缩进 2 个空格
const prettyJson = JSON.stringify(obj, null, 2);
console.log(prettyJson);

// 使用 replacer 过滤属性
const filtered = JSON.stringify(obj, ['name', 'age']);
console.log(filtered); // {"name":"张三","age":25}

// JSON.parse() - 将 JSON 字符串转为对象
const parsed = JSON.parse(jsonStr);
console.log(parsed.name); // 张三

// 使用 reviver 转换值
const jsonWithDate = '{"date":"2024-01-01T00:00:00.000Z"}';
const objWithDate = JSON.parse(jsonWithDate, (key, value) => {
  if (key === 'date') return new Date(value);
  return value;
});
console.log(objWithDate.date instanceof Date); // true

注意事项

// 1. JSON 键名必须是双引号字符串
// 正确:{"name": "张三"}
// 错误:{name: "张三"} 或 {'name': '张三'}

// 2. 不支持的类型会被忽略或转为 null
const special = {
  fn: function() {},    // 函数 - 被忽略
  undef: undefined,     // undefined - 被忽略
  sym: Symbol('id'),    // Symbol - 被忽略
  date: new Date(),     // Date - 转为字符串
  regex: /abc/,         // RegExp - 转为空对象 {}
  nan: NaN,             // NaN - 转为 null
  infinity: Infinity    // Infinity - 转为 null
};

console.log(JSON.stringify(special));
// {"date":"2024-...","regex":{},"nan":null,"infinity":null}

// 3. 循环引用会报错
const circular = { name: '张三' };
circular.self = circular;
// JSON.stringify(circular); // TypeError: Converting circular structure to JSON

// 4. toJSON 方法可自定义序列化
const user = {
  name: '张三',
  password: '123456',
  toJSON() {
    return { name: this.name }; // 隐藏密码
  }
};
console.log(JSON.stringify(user)); // {"name":"张三"}

深拷贝的局限性

// JSON 方式实现深拷贝
const original = {
  name: '张三',
  info: { age: 25 }
};

const cloned = JSON.parse(JSON.stringify(original));
cloned.info.age = 30;

console.log(original.info.age); // 25 - 原对象不受影响

// 但无法处理特殊类型
const withSpecial = {
  date: new Date(),
  fn: () => {},
  undef: undefined
};

const clonedSpecial = JSON.parse(JSON.stringify(withSpecial));
console.log(clonedSpecial);
// { date: "2024-..." } - date 变成字符串,fn 和 undef 丢失

关键点

  • JSON 键名必须用双引号,值的字符串也必须用双引号
  • JSON.stringify() 会忽略函数、undefined、Symbol
  • JSON.parse() 的 reviver 参数可用于转换特殊类型(如日期)
  • JSON 深拷贝无法处理循环引用、函数、Date、RegExp 等类型
  • 对象可通过 toJSON() 方法自定义序列化行为