什么是 JSON?
JSON(JavaScript Object Notation,JavaScript 对象表示法)是一种轻量级的文本数据交换格式,既便于人类阅读和编写,也易于机器解析和生成。尽管 JSON 语法源自 JavaScript,但它是语言无关的——几乎所有现代编程语言都提供了解析和生成 JSON 的标准库。
JSON 由 Douglas Crockford 在 21 世纪初提出,作为 XML 的更简洁替代方案用于 Web 数据交换。如今,它已成为 REST API、配置文件、MongoDB 等 NoSQL 数据库以及众多领域的主流格式。
JSON 语法:完整介绍
JSON 值可以是以下类型之一:
- 对象:
{ "key": value, ... }— 键值对的无序集合,键必须是字符串 - 数组:
[ value, ... ]— 有序值列表 - 字符串:
"hello world"— 必须使用双引号 - 数字:
42、3.14、-7、1.5e10— 不区分整数与浮点数 - 布尔值:
true或false - 空值:
null
{
"name": "张三",
"age": 30,
"isActive": true,
"scores": [95, 87, 100],
"address": {
"city": "北京",
"district": "海淀区"
},
"notes": null
}
常见语法错误
| 错误类型 | 错误写法 | 正确写法 |
|---|---|---|
| 尾部逗号 | { "a": 1, } |
{ "a": 1 } |
| 单引号 | { 'key': 'val' } |
{ "key": "val" } |
| 键未加引号 | { key: "val" } |
{ "key": "val" } |
| 注释 | { // 注释 } |
(JSON 不支持注释) |
| undefined | { "a": undefined } |
使用 null 或省略该键 |
简史
- 2001 年:Douglas Crockford 开始推广 JSON 作为无状态的服务器到浏览器通信协议
- 2006 年:IETF 发布 RFC 4627,JSON 的第一个正式规范
- 2013 年:ECMA International 将 JSON 标准化为 ECMA-404
- 2017 年:RFC 8259 取代所有先前 RFC,成为权威标准
在 JSON 出现之前,XML 主导了 API 通信。JSON 的简洁性和与 JavaScript 对象的天然契合使其在 Web 2.0 时代迅速普及——这一趋势延续至今。
JSON 的应用场景
REST API
如今几乎所有 REST API 都返回 JSON 格式数据。以天气 API 为例:
{
"location": "北京",
"temperature": 26.5,
"unit": "celsius",
"conditions": ["晴天", "微风"],
"forecast": [
{ "day": "周一", "high": 28, "low": 18 },
{ "day": "周二", "high": 25, "low": 16 }
]
}
配置文件
ESLint(.eslintrc.json)、TypeScript(tsconfig.json)、npm(package.json)等工具均使用 JSON 作为配置格式。
NoSQL 数据库
MongoDB 以 BSON(Binary JSON)存储文档。CouchDB、Firebase Firestore、DynamoDB 等数据库也采用类 JSON 的文档模型。
浏览器本地存储
浏览器的 localStorage 只能存储字符串,开发者通常在存储前使用 JSON.stringify() 序列化对象,读取时用 JSON.parse() 反序列化。
结构化日志
以 JSON 格式记录日志便于使用 Elasticsearch、Datadog 或 Loki 等工具进行查询分析。
各语言的 JSON 解析
JavaScript / TypeScript
// 解析字符串为对象
const data = JSON.parse('{"name":"张三","age":30}');
console.log(data.name); // "张三"
// 序列化为字符串(美化输出)
const json = JSON.stringify({ name: "张三", age: 30 }, null, 2);
JSON.stringify 的第三个参数 2 表示用 2 个空格缩进,调试时非常实用。
Python
import json
# 解析
data = json.loads('{"name": "张三", "age": 30}')
print(data["name"]) # 张三
# 序列化
text = json.dumps({"name": "张三", "age": 30}, ensure_ascii=False, indent=2)
注意 Python 中需设置 ensure_ascii=False 才能正确输出中文字符。
Go
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
var p Person
json.Unmarshal([]byte(`{"name":"张三","age":30}`), &p)
fmt.Println(p.Name)
}
进阶主题
JSON Schema
JSON Schema 是验证 JSON 数据结构的词汇表,可以定义必填字段、值类型、模式和约束:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer", "minimum": 0 }
},
"required": ["name", "age"]
}
JSON Pointer(RFC 6901)
JSON Pointer 提供了一种字符串语法,用于定位 JSON 文档中的特定值:
/name→name字段/scores/0→scores数组的第一个元素
JSON Patch(RFC 6902)
JSON Patch 定义了一套对 JSON 文档进行增量更新的操作格式,适用于 API 中的部分更新场景。
性能考量
- 数据量:JSON 是文本格式,相对冗长。高吞吐场景可考虑 MessagePack 或 Protocol Buffers 等二进制替代方案。
- 解析速度:现代 JSON 解析器(如 simdjson)每秒可处理数 GB 数据,对大多数 Web 应用而言解析性能不是瓶颈。
- 深层嵌套:嵌套过深可能导致递归解析器栈溢出,建议保持数据结构尽量扁平。
JSON vs XML vs YAML
| 特性 | JSON | XML | YAML |
|---|---|---|---|
| 可读性 | 良好 | 冗长 | 极佳 |
| 支持注释 | ❌ | ✅ | ✅ |
| 二进制支持 | ❌(需 base64) | ❌ | ❌ |
| Schema 验证 | JSON Schema | XSD | ❌(有限) |
| 最适合 | API、配置、存储 | 文档、历史系统 | 配置文件 |
最佳实践
- 输入时验证:始终对外部 JSON 输入进行验证,绝不盲目信任。
null的使用要有意义:区分"字段缺失"与"字段值为 null"。- 避免深层嵌套:扁平化数据结构更易于处理,用 ID 引用关联对象。
- 统一键名风格:在整个 API 中选择一种风格(camelCase 或 snake_case)并保持一致。
- 日期使用 ISO 8601 字符串:JSON 没有日期类型,推荐使用
"2025-04-09T00:00:00Z"格式。 - 生产环境压缩,调试时美化:API 响应使用紧凑 JSON 以节省带宽;本地调试时使用格式化输出。
小结
JSON 因其简洁性、可读性和广泛的语言支持,已成为 Web 数据交换的通用语言。深入理解 JSON 的语法、局限性和最佳实践,无论是构建 API、编写配置文件还是处理数据管道,都会让你成为更高效的开发者。