Skip to content

JSON 处理

JSON(JavaScript Object Notation)是轻量级的数据交换格式。它基于 JavaScript 对象语法,但独立于语言,被广泛用于前后端数据传输。

🎯 JSON 语法#

基本规则#

// JSON 是纯文本格式
const jsonString = '{"name": "张三", "age": 25}'
// 合法的 JSON 值类型:
// - 字符串(必须用双引号)
// - 数字
// - 布尔值(true/false)
// - null
// - 数组
// - 对象
// ✅ 合法 JSON
;('{"name": "张三"}')
;('[1, 2, 3]')
;('"hello"')
;('123')
;('true')
;('null')
// 🔶 不合法 JSON
;("{'name': '张三'}") // 单引号不行
;('{name: "张三"}') // 键必须用双引号
;('undefined') // undefined 不是 JSON 值
;('{a: function(){}}') // 函数不是 JSON 值

与 JavaScript 对象的区别#

// JavaScript 对象
const jsObject = {
'name': '张三', // 键不需要引号
'my-age': 25, // 特殊键需要引号
'sayHi'() {}, // 可以有方法
'date': new Date(), // 可以有 Date 对象
'regex': /abc/, // 可以有正则
'undefined': undefined,
}
// JSON 字符串
const jsonString = `{
"name": "张三",
"my-age": 25
}`
// 不能有方法、Date、正则、undefined

JSON.parse#

基本用法#

// 将 JSON 字符串解析为 JavaScript 值
const jsonString = '{"name": "张三", "age": 25}'
const obj = JSON.parse(jsonString)
console.log(obj.name) // '张三'
console.log(obj.age) // 25
// 解析数组
const arrString = '[1, 2, 3]'
const arr = JSON.parse(arrString)
console.log(arr) // [1, 2, 3]
// 解析基本类型
JSON.parse('"hello"') // 'hello'
JSON.parse('123') // 123
JSON.parse('true') // true
JSON.parse('null') // null

错误处理#

// 🔶 解析无效 JSON 会抛出错误
try {
JSON.parse('invalid json')
} catch (error) {
console.log(error.message) // Unexpected token...
}
// 安全的解析���数
function safeJsonParse(str, defaultValue = null) {
try {
return JSON.parse(str)
} catch {
return defaultValue
}
}
safeJsonParse('{"valid": true}') // { valid: true }
safeJsonParse('invalid') // null
safeJsonParse('invalid', {}) // {}

reviver 函数#

// 第二个参数可以转换解析结果
const jsonString = '{"name": "张三", "birthDate": "1990-05-20"}'
const obj = JSON.parse(jsonString, (key, value) => {
// key 是属性名,value 是属性值
if (key === 'birthDate') {
return new Date(value) // 转为 Date 对象
}
return value
})
console.log(obj.birthDate instanceof Date) // true
// 过滤属性
const filtered = JSON.parse('{"a": 1, "b": 2, "c": 3}', (key, value) => {
if (key === 'b') return undefined // 排除 b
return value
})
console.log(filtered) // { a: 1, c: 3 }

JSON.stringify#

基本用法#

// 将 JavaScript 值转为 JSON 字符串
const obj = { name: '张三', age: 25 }
const jsonString = JSON.stringify(obj)
console.log(jsonString) // '{"name":"张三","age":25}'
// 转换数组
JSON.stringify([1, 2, 3]) // '[1,2,3]'
// 转换基本类型
JSON.stringify('hello') // '"hello"'
JSON.stringify(123) // '123'
JSON.stringify(true) // 'true'
JSON.stringify(null) // 'null'

特殊值处理#

// undefined、函数、Symbol 会被忽略或转为 null
const obj = {
a: undefined,
b: function () {},
c: Symbol('sym'),
d: 'valid',
}
JSON.stringify(obj) // '{"d":"valid"}'
// 在数组中会转为 null
JSON.stringify([undefined, function () {}, Symbol()])
// '[null,null,null]'
// NaN 和 Infinity 转为 null
JSON.stringify(NaN) // 'null'
JSON.stringify(Infinity) // 'null'
// Date 转为 ISO 字符串
JSON.stringify(new Date()) // '"2025-01-15T02:30:00.000Z"'
// 正则转为空对象
JSON.stringify(/abc/) // '{}'

replacer 参数#

// 数组形式:只包含指定属性
const obj = { a: 1, b: 2, c: 3 }
JSON.stringify(obj, ['a', 'b']) // '{"a":1,"b":2}'
// 函数形式:自定义转换
const data = {
name: '张三',
password: '123456',
age: 25,
}
const result = JSON.stringify(data, (key, value) => {
if (key === 'password') {
return undefined // 排除密码
}
if (typeof value === 'number') {
return value * 2 // 数字翻倍
}
return value
})
console.log(result) // '{"name":"张三","age":50}'

space 参数(格式化)#

const obj = { name: '张三', info: { age: 25, city: '北京' } }
// 使用 2 个空格缩进
console.log(JSON.stringify(obj, null, 2))
/*
{
"name": "张三",
"info": {
"age": 25,
"city": "北京"
}
}
*/
// 使用 tab 缩进
console.log(JSON.stringify(obj, null, '\t'))
// 使用 4 个空格
console.log(JSON.stringify(obj, null, 4))

toJSON 方法#

// 对象可以定义 toJSON 方法自定义序列化
const user = {
name: '张三',
password: '123456',
toJSON() {
return {
name: this.name,
// 不包含 password
}
},
}
JSON.stringify(user) // '{"name":"张三"}'
// Date 内置了 toJSON
const date = new Date()
date.toJSON() // '2025-01-15T02:30:00.000Z'

深拷贝#

JSON 方式#

// 使用 JSON 实现深拷贝
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj))
}
const original = {
name: '张三',
info: { age: 25 },
}
const cloned = deepClone(original)
cloned.info.age = 30
console.log(original.info.age) // 25(原对象未变)
console.log(cloned.info.age) // 30

🔶 JSON 深拷贝的限制#

const obj = {
date: new Date(), // 变成字符串
regex: /abc/, // 变成空对象
func: function () {}, // 丢失
undef: undefined, // 丢失
symbol: Symbol('sym'), // 丢失
nan: NaN, // 变成 null
infinity: Infinity, // 变成 null
circular: null, // 循环引用会报错
}
// obj.circular = obj // 循环引用
// JSON.stringify(obj) // TypeError: Converting circular structure to JSON
const cloned = JSON.parse(JSON.stringify(obj))
console.log(cloned)
// {
// date: '2025-01-15T02:30:00.000Z',
// regex: {},
// nan: null,
// infinity: null
// }

更完善的深拷贝#

function deepClone(obj, hash = new WeakMap()) {
// 处理 null 和非对象
if (obj === null || typeof obj !== 'object') {
return obj
}
// 处理 Date
if (obj instanceof Date) {
return new Date(obj)
}
// 处理 RegExp
if (obj instanceof RegExp) {
return new RegExp(obj)
}
// 处理循环引用
if (hash.has(obj)) {
return hash.get(obj)
}
// 处理数组和对象
const cloned = Array.isArray(obj) ? [] : {}
hash.set(obj, cloned)
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
cloned[key] = deepClone(obj[key], hash)
}
}
return cloned
}
// 现代方法:structuredClone(浏览器和 Node.js 17+)
const cloned = structuredClone(obj)

实际应用#

本地存储#

// 存储对象到 localStorage
const user = { name: '张三', age: 25, preferences: { theme: 'dark' } }
// 存储
localStorage.setItem('user', JSON.stringify(user))
// 读取
const stored = localStorage.getItem('user')
const parsedUser = stored ? JSON.parse(stored) : null
// 封装
const storage = {
set(key, value) {
localStorage.setItem(key, JSON.stringify(value))
},
get(key, defaultValue = null) {
const item = localStorage.getItem(key)
try {
return item ? JSON.parse(item) : defaultValue
} catch {
return defaultValue
}
},
remove(key) {
localStorage.removeItem(key)
},
}
storage.set('config', { theme: 'dark' })
storage.get('config') // { theme: 'dark' }

API 数据处理#

// 发送 JSON 数据
async function postData(url, data) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
return response.json() // 自动解析 JSON
}
// 处理响应
async function fetchUser(id) {
const response = await fetch(`/api/users/${id}`)
const data = await response.json()
// 转换日期字段
return {
...data,
createdAt: new Date(data.createdAt),
updatedAt: new Date(data.updatedAt),
}
}

日志和调试#

// 格式化输出对象
function prettyPrint(obj) {
console.log(JSON.stringify(obj, null, 2))
}
// 带时间戳的日志
function log(message, data) {
console.log(
JSON.stringify(
{
timestamp: new Date().toISOString(),
message,
data,
},
null,
2
)
)
}
log('��户登录', { userId: 123, ip: '192.168.1.1' })

比较对象#

// 简单对象比较(有局限性)
function simpleEqual(obj1, obj2) {
return JSON.stringify(obj1) === JSON.stringify(obj2)
}
simpleEqual({ a: 1, b: 2 }, { a: 1, b: 2 }) // true
// 🔶 注意:属性顺序会影响结果
simpleEqual({ a: 1, b: 2 }, { b: 2, a: 1 }) // false
// 改进版:排序键
function sortedStringify(obj) {
return JSON.stringify(obj, Object.keys(obj).sort())
}
// 更好的方式:深度比较函数
function deepEqual(a, b) {
if (a === b) return true
if (typeof a !== 'object' || typeof b !== 'object') return false
if (a === null || b === null) return false
const keysA = Object.keys(a)
const keysB = Object.keys(b)
if (keysA.length !== keysB.length) return false
return keysA.every((key) => deepEqual(a[key], b[key]))
}

配置文件处理#

// 合并配置
function mergeConfig(defaults, custom) {
// 深拷贝默认配置
const config = JSON.parse(JSON.stringify(defaults))
// 递归合并
function merge(target, source) {
for (const key in source) {
if (
source[key] &&
typeof source[key] === 'object' &&
!Array.isArray(source[key])
) {
target[key] = target[key] || {}
merge(target[key], source[key])
} else {
target[key] = source[key]
}
}
return target
}
return merge(config, custom)
}
const defaults = {
theme: 'light',
language: 'zh',
features: { darkMode: false, animations: true },
}
const custom = {
theme: 'dark',
features: { darkMode: true },
}
mergeConfig(defaults, custom)
// { theme: 'dark', language: 'zh', features: { darkMode: true, animations: true } }

性能优化#

大数据处理#

// 🔶 大对象序列化可能阻塞主线程
const hugeArray = new Array(100000).fill({ data: 'some data' })
// 考虑使用 Web Worker
const worker = new Worker('json-worker.js')
worker.postMessage({ action: 'stringify', data: hugeArray })
worker.onmessage = (e) => {
const jsonString = e.data
}
// 或分批处理
async function stringifyLargeArray(arr, batchSize = 1000) {
const chunks = []
for (let i = 0; i < arr.length; i += batchSize) {
chunks.push(JSON.stringify(arr.slice(i, i + batchSize)))
await new Promise((resolve) => setTimeout(resolve, 0)) // 让出主线程
}
return '[' + chunks.map((c) => c.slice(1, -1)).join(',') + ']'
}

选择性序列化#

// 只序列化需要的字段
const user = {
id: 1,
name: '张三',
password: 'secret',
profile: {
/* 大量数据 */
},
logs: [
/* 更多数据 */
],
}
// 使用 replacer 数组
JSON.stringify(user, ['id', 'name']) // '{"id":1,"name":"张三"}'

总结#

方法说明
JSON.parse(str)解析 JSON 字符串
JSON.parse(str, reviver)带转换函数的解析
JSON.stringify(obj)转为 JSON 字符串
JSON.stringify(obj, replacer)带过滤的序列化
JSON.stringify(obj, null, space)格式化输出
类型stringify 结果
undefined被忽略/null
function被忽略/null
Symbol被忽略/null
DateISO 字符串
RegExp空对象 {}
NaN/Infinitynull

核心要点