JSON.stringify 基础与进阶用法完全攻略
作者:珍宝商店
掌握JSON.stringify核心功能,包括数据类型支持、嵌套处理、循环引用检测、格式化输出及安全性保障,适用于API传输、配置生成等场景,助开发者高效处理数据,本文给大家介绍JSON.stringify基础与进阶用法完全攻略,感兴趣的朋友跟随小编一起看看吧
JSON.stringify 基础与进阶用法指南
关键特性概览
🚀 核心能力
JSON.stringify 是 JavaScript 内置的序列化方法,具有以下关键特性:
1.通用序列化支持
- ✅ 支持所有 JSON 兼容的数据类型
- ✅ 自动处理嵌套对象和数组
- ✅ 保持数据结构的完整性
- ✅ 自动忽略 undefined、Symbol 和函数类型的属性
- ✅ 只序列化对象自身的可枚举属性
- ✅ 日期对象还没转化为 ISO 格式字符串
- ✅ 循环引用会抛出错误
// 支持复杂数据结构
const complexData = {
users: [
{ id: 1, name: '张三', active: true },
{ id: 2, name: '李四', active: false },
],
metadata: {
total: 2,
timestamp: '2025-09-15T10:30:00.000Z',
},
};
// 一键序列化
JSON.stringify(complexData);2.灵活的数据转换
- 🔧 Replacer 函数自定义转换逻辑
- 🔧 白名单模式精确控制输出
- 🔧 toJSON 方法实现对象级别控制
// 多种转换方式
const data = { name: '测试', password: 'secret', age: 25 };
// 方式1:函数过滤
JSON.stringify(data, (k, v) => (k === 'password' ? undefined : v));
// 方式2:白名单模式
JSON.stringify(data, ['name', 'age']);
// 方式3:对象自定义
data.toJSON = () => ({ name: data.name, age: data.age });3.智能格式化输出
- 📋 支持缩进美化
- 📋 自定义缩进字符
- 📋 压缩与可读性平衡
const obj = { a: 1, b: { c: 2 } };
// 压缩输出
JSON.stringify(obj); // {"a":1,"b":{"c":2}}
// 美化输出
JSON.stringify(obj, null, 2);
/*
{
"a": 1,
"b": {
"c": 2
}
}
*/
// 自定义缩进
JSON.stringify(obj, null, '→');
/*
{
→"a": 1,
→"b": {
→→"c": 2
→}
}
*/4.安全性保障
- 🛡️ 自动过滤不安全的数据类型
- 🛡️ 防止代码注入
- 🛡️ 循环引用检测(需自定义处理)
const unsafeData = {
name: '用户',
method: function () {
return 'danger';
}, // 被忽略
symbol: Symbol('test'), // 被忽略
undef: undefined, // 被忽略
safe: 'normal string', // 保留
};
JSON.stringify(unsafeData);
// 输出: {"name":"用户","safe":"normal string"}🎯 核心优势
| 特性 | 描述 | 应用场景 |
|---|---|---|
| 原生支持 | 浏览器和 Node.js 内置 | 无需额外依赖 |
| 高性能 | C++ 底层实现,速度快 | 大数据序列化 |
| 标准兼容 | 严格遵循 JSON 规范 | 跨平台数据交换 |
| 灵活配置 | 多参数精确控制 | 复杂业务需求 |
| 错误处理 | 明确的异常机制 | 生产环境稳定性 |
⚡ 性能特点
// 性能基准测试示例
function benchmarkStringify() {
const testData = new Array(10000).fill(0).map((_, i) => ({
id: i,
name: `用户${i}`,
score: Math.random() * 100,
active: i % 2 === 0,
}));
console.time('JSON.stringify');
const result = JSON.stringify(testData);
console.timeEnd('JSON.stringify');
console.log(`数据大小: ${result.length} 字符`);
console.log(
`压缩率: ${(
(result.length / JSON.stringify(testData, null, 2).length) *
100
).toFixed(1)}%`
);
}
benchmarkStringify();
// 典型输出:
// JSON.stringify: 15.234ms
// 数据大小: 889123 字符
// 压缩率: 45.2%🔍 兼容性矩阵
| 环境 | 版本支持 | 特性完整度 | 备注 |
|---|---|---|---|
| Chrome | 4+ | 100% | 完全支持 |
| Firefox | 3.5+ | 100% | 完全支持 |
| Safari | 4+ | 100% | 完全支持 |
| IE | 8+ | 100% | 原生支持 |
| Node.js | 0.1+ | 100% | 服务端支持 |
| React Native | 全版本 | 100% | 移动端支持 |
🛠️ 扩展能力
// 扩展 JSON.stringify 功能示例
class EnhancedJSON {
static stringify(obj, options = {}) {
const {
// 基础选项
replacer = null,
space = null,
// 扩展选项
maxDepth = Infinity,
dateFormat = 'iso', // 'iso' | 'timestamp' | 'locale'
errorHandler = 'throw', // 'throw' | 'skip' | 'placeholder'
bigintSupport = false, // 是否支持 BigInt
functionSupport = false, // 是否保留函数
// 安全选项
sensitiveKeys = ['password', 'token', 'secret'],
maxSize = 1024 * 1024, // 最大 1MB
// 性能选项
cache = false, // 是否启用缓存
stream = false, // 是否流式处理
} = options;
// 实现增强的序列化逻辑...
return this._enhancedStringify(obj, {
replacer,
space,
maxDepth,
dateFormat,
errorHandler,
bigintSupport,
functionSupport,
sensitiveKeys,
maxSize,
cache,
stream,
});
}
static _enhancedStringify(obj, options) {
// 详细实现逻辑...
// 这里可以添加各种增强功能
}
}基础语法
JSON.stringify(value[, replacer[, space]])
参数说明:
value: 要序列化的值replacer(可选): 转换器函数或数组,用于过滤和转换结果space(可选): 用于美化输出的空白字符
基础用法
1. 简单对象序列化
const obj = {
name: '张三',
age: 25,
city: '北京',
};
console.log(JSON.stringify(obj));
// 输出: {"name":"张三","age":25,"city":"北京"}2. 数组序列化
const arr = [1, 2, 3, 'hello', true]; console.log(JSON.stringify(arr)); // 输出: [1,2,3,"hello",true]
3. 嵌套对象序列化
const complexObj = {
user: {
name: '李四',
profile: {
age: 30,
hobbies: ['读书', '游泳', '编程'],
},
},
timestamp: new Date(),
};
console.log(JSON.stringify(complexObj));
// 输出: {"user":{"name":"李四","profile":{"age":30,"hobbies":["读书","游泳","编程"]}},"timestamp":"2025-09-15T10:30:00.000Z"}进阶用法
1. toJSON 方法
对象可以定义 toJSON 方法来自定义序列化行为:
class User {
constructor(name, password, email) {
this.name = name;
this.password = password;
this.email = email;
}
toJSON() {
// 排除敏感信息
return {
name: this.name,
email: this.email,
};
}
}
const user = new User('王五', 'secret123', 'wangwu@example.com');
console.log(JSON.stringify(user));
// 输出: {"name":"王五","email":"wangwu@example.com"}2. Date 对象的处理
const dateObj = {
created: new Date(),
updated: new Date('2024-01-01'),
};
console.log(JSON.stringify(dateObj));
// 输出: {"created":"2025-09-15T10:30:00.000Z","updated":"2024-01-01T00:00:00.000Z"}
// 自定义 Date 序列化
Date.prototype.toJSON = function () {
return this.getTime(); // 返回时间戳
};
console.log(JSON.stringify(dateObj));
// 输出: {"created":1726397400000,"updated":1704067200000}选择性序列化
选择性序列化是 JSON.stringify 最强大的功能之一,允许我们精确控制哪些数据被序列化,如何转换数据,以及输出格式。
🎯 核心概念
选择性序列化主要通过以下三种方式实现:
- Replacer 函数 - 逐个处理每个键值对
- Replacer 数组 - 白名单模式指定属性
- toJSON 方法 - 对象级别的自定义序列化
1. 基于函数的选择性序列化
1.1 基础过滤
const userData = {
id: 1001,
username: 'zhangsan',
password: 'secret123',
email: 'zhangsan@example.com',
phone: '13800138000',
role: 'admin',
lastLogin: new Date(),
settings: {
theme: 'dark',
notifications: true,
apiKey: 'sk-1234567890abcdef',
},
};
// 基础敏感信息过滤
const publicData = JSON.stringify(userData, (key, value) => {
// 过滤敏感字段
const sensitiveKeys = ['password', 'apiKey'];
if (sensitiveKeys.includes(key)) {
return undefined; // 完全移除
}
return value;
});
console.log(publicData);
// 输出: {"id":1001,"username":"zhangsan","email":"zhangsan@example.com",...}1.2 数据脱敏
const sensitiveData = {
name: '张三',
idCard: '110101199001011234',
phone: '13800138000',
email: 'zhangsan@example.com',
bankCard: '6222021234567890123',
salary: 15000,
};
// 数据脱敏处理
const maskedData = JSON.stringify(sensitiveData, (key, value) => {
switch (key) {
case 'idCard':
// 身份证脱敏:显示前6位和后4位
return value.replace(/(\d{6})\d*(\d{4})/, '$1******$2');
case 'phone':
// 手机号脱敏:显示前3位和后4位
return value.replace(/(\d{3})\d*(\d{4})/, '$1****$2');
case 'email':
// 邮箱脱敏:用户名部分脱敏
return value.replace(/(.{2}).*(@.*)/, '$1***$2');
case 'bankCard':
// 银行卡脱敏:只显示后4位
return '****' + value.slice(-4);
case 'salary':
// 薪资脱敏:转为范围
const salaryRange = Math.floor(value / 5000) * 5000;
return `${salaryRange}-${salaryRange + 4999}`;
default:
return value;
}
});
console.log(JSON.parse(maskedData));
// 输出: {
// name: "张三",
// idCard: "110101******1234",
// phone: "138****8000",
// email: "zh***@example.com",
// bankCard: "****0123",
// salary: "15000-19999"
// }1.3 条件序列化
const productData = {
id: 'p001',
name: 'iPhone 15',
price: 7999,
cost: 4500, // 内部成本,不对外
inventory: 150,
status: 'active',
internal: {
supplier: 'Apple Inc',
margin: 43.7, // 利润率,敏感信息
notes: 'Q4 热销产品',
},
public: {
description: '最新款智能手机',
features: ['A17 芯片', '48MP 相机', '128GB 存储'],
},
};
// 根据用户权限选择性序列化
function createProductSerializer(userRole) {
return (key, value) => {
// 所有用户都不能看到的字段
if (['cost'].includes(key)) {
return undefined;
}
// 只有管理员能看到的字段
if (userRole !== 'admin') {
if (['internal', 'margin'].includes(key)) {
return undefined;
}
}
// 特殊处理
if (key === 'inventory' && userRole === 'customer') {
// 客户只能看到库存状态,不能看到具体数量
return value > 0 ? '有库存' : '无库存';
}
return value;
};
}
// 管理员视图
const adminView = JSON.stringify(
productData,
createProductSerializer('admin'),
2
);
// 客户视图
const customerView = JSON.stringify(
productData,
createProductSerializer('customer'),
2
);
console.log('管理员视图:', adminView);
console.log('客户视图:', customerView);2. 基于数组的选择性序列化
2.1 白名单模式
const fullUserProfile = {
// 基本信息
id: 1001,
username: 'zhangsan',
email: 'zhangsan@example.com',
// 敏感信息
password: 'secret123',
ssn: '123-45-6789',
// 个人信息
firstName: '三',
lastName: '张',
age: 28,
// 系统信息
createdAt: '2024-01-01T00:00:00.000Z',
updatedAt: '2025-09-15T10:30:00.000Z',
isActive: true,
// 配置信息
preferences: {
language: 'zh-CN',
timezone: 'Asia/Shanghai',
theme: 'dark',
},
};
// 定义不同场景的字段白名单
const whitelists = {
// 公开资料
public: ['id', 'username', 'firstName', 'lastName'],
// 个人资料编辑
profile: [
'id',
'username',
'email',
'firstName',
'lastName',
'age',
'preferences',
],
// 系统管理
admin: ['id', 'username', 'email', 'isActive', 'createdAt', 'updatedAt'],
// API 响应
api: ['id', 'username', 'email', 'firstName', 'lastName', 'isActive'],
};
// 使用不同白名单
Object.entries(whitelists).forEach(([scenario, fields]) => {
const result = JSON.stringify(fullUserProfile, fields, 2);
console.log(`${scenario} 场景:`, result);
});2.2 动态白名单
class FieldSelector {
constructor() {
this.baseFields = ['id', 'name', 'type'];
this.conditionalFields = new Map();
}
// 添加条件字段
addConditionalField(condition, fields) {
this.conditionalFields.set(condition, fields);
return this;
}
// 生成字段列表
getFields(context = {}) {
let fields = [...this.baseFields];
for (const [condition, additionalFields] of this.conditionalFields) {
if (typeof condition === 'function' && condition(context)) {
fields.push(...additionalFields);
} else if (typeof condition === 'string' && context[condition]) {
fields.push(...additionalFields);
}
}
return [...new Set(fields)]; // 去重
}
}
const productSelector = new FieldSelector()
.addConditionalField((ctx) => ctx.userRole === 'admin', ['cost', 'supplier'])
.addConditionalField(
(ctx) => ctx.showDetails,
['description', 'specifications']
)
.addConditionalField('includeStock', ['inventory', 'reserved']);
const product = {
id: 'p001',
name: 'MacBook Pro',
type: 'laptop',
price: 12999,
cost: 8000,
supplier: 'Apple',
inventory: 50,
reserved: 5,
description: '专业级笔记本电脑',
specifications: { cpu: 'M3', ram: '16GB', storage: '512GB' },
};
// 不同上下文的序列化
const contexts = [
{ userRole: 'customer', showDetails: false },
{ userRole: 'admin', showDetails: true, includeStock: true },
{ userRole: 'sales', showDetails: true },
];
contexts.forEach((context, index) => {
const fields = productSelector.getFields(context);
const result = JSON.stringify(product, fields, 2);
console.log(`Context ${index + 1}:`, result);
});3. 基于 toJSON 的选择性序列化
3.1 智能对象序列化
class SmartUser {
constructor(data) {
Object.assign(this, data);
this._sensitive = ['password', 'ssn', 'creditCard'];
this._internal = ['_sensitive', '_internal', '_context'];
}
// 设置序列化上下文
setContext(context) {
this._context = context;
return this;
}
toJSON() {
const result = {};
const context = this._context || {};
for (const [key, value] of Object.entries(this)) {
// 跳过内部字段
if (this._internal.includes(key)) continue;
// 处理敏感字段
if (this._sensitive.includes(key)) {
if (context.includeSensitive) {
result[key] = context.maskSensitive
? this._maskValue(key, value)
: value;
}
continue;
}
// 处理嵌套对象
if (value && typeof value === 'object' && value.toJSON) {
result[key] = value.toJSON();
} else {
result[key] = value;
}
}
return result;
}
_maskValue(key, value) {
switch (key) {
case 'password':
return '***';
case 'ssn':
return value.replace(/\d/g, '*');
case 'creditCard':
return value.replace(/\d(?=\d{4})/g, '*');
default:
return value;
}
}
}
const user = new SmartUser({
id: 1001,
name: '张三',
email: 'zhangsan@example.com',
password: 'secret123',
ssn: '123-45-6789',
role: 'user',
});
// 不同上下文的序列化
console.log('默认序列化:', JSON.stringify(user, null, 2));
console.log(
'包含敏感信息:',
JSON.stringify(user.setContext({ includeSensitive: true }), null, 2)
);
console.log(
'脱敏序列化:',
JSON.stringify(
user.setContext({ includeSensitive: true, maskSensitive: true }),
null,
2
)
);3.2 多版本序列化
class VersionedData {
constructor(data) {
this.data = data;
this.versions = new Map();
}
// 注册版本序列化器
registerVersion(version, serializer) {
this.versions.set(version, serializer);
return this;
}
// 设置当前版本
setVersion(version) {
this.currentVersion = version;
return this;
}
toJSON() {
const version = this.currentVersion || 'default';
const serializer = this.versions.get(version);
if (serializer) {
return serializer(this.data);
}
return this.data;
}
}
const apiData = new VersionedData({
id: 1001,
username: 'zhangsan',
email: 'zhangsan@example.com',
profile: {
firstName: '三',
lastName: '张',
age: 28,
avatar: 'https://example.com/avatar.jpg',
},
settings: {
theme: 'dark',
language: 'zh-CN',
},
createdAt: new Date('2024-01-01'),
updatedAt: new Date(),
});
// 注册不同版本的序列化器
apiData
.registerVersion('v1', (data) => ({
id: data.id,
name: data.username,
email: data.email,
created: data.createdAt.toISOString(),
}))
.registerVersion('v2', (data) => ({
id: data.id,
username: data.username,
email: data.email,
profile: {
name: `${data.profile.lastName}${data.profile.firstName}`,
age: data.profile.age,
avatar: data.profile.avatar,
},
metadata: {
created: data.createdAt.toISOString(),
updated: data.updatedAt.toISOString(),
},
}))
.registerVersion('v3', (data) => ({
user: {
id: data.id,
username: data.username,
email: data.email,
profile: data.profile,
preferences: data.settings,
},
timestamps: {
createdAt: data.createdAt.getTime(),
updatedAt: data.updatedAt.getTime(),
},
}));
// 使用不同版本
['v1', 'v2', 'v3'].forEach((version) => {
console.log(
`API ${version}:`,
JSON.stringify(apiData.setVersion(version), null, 2)
);
});🛠️ 实用工具类
// 选择性序列化工具类
class SelectiveStringify {
static create() {
return new SelectiveStringify();
}
constructor() {
this.rules = [];
this.globalOptions = {};
}
// 添加字段规则
field(fieldPath, rule) {
this.rules.push({ path: fieldPath, rule });
return this;
}
// 排除字段
exclude(...fields) {
fields.forEach((field) => this.field(field, () => undefined));
return this;
}
// 包含字段
include(...fields) {
this.includeOnly = new Set(fields);
return this;
}
// 脱敏字段
mask(field, maskFn) {
this.field(field, (value) => (maskFn ? maskFn(value) : '***'));
return this;
}
// 转换字段
transform(field, transformFn) {
this.field(field, transformFn);
return this;
}
// 条件字段
when(field, condition, thenRule, elseRule) {
this.field(field, (value, context) => {
const shouldApply =
typeof condition === 'function'
? condition(value, context)
: context[condition];
return shouldApply
? typeof thenRule === 'function'
? thenRule(value, context)
: thenRule
: typeof elseRule === 'function'
? elseRule(value, context)
: elseRule;
});
return this;
}
// 执行序列化
stringify(obj, context = {}, space = null) {
const replacer = (key, value) => {
if (key === '') return value;
// 包含字段检查
if (this.includeOnly && !this.includeOnly.has(key)) {
return undefined;
}
// 应用字段规则
for (const { path, rule } of this.rules) {
if (this.matchPath(key, path)) {
const result = rule(value, context);
if (result !== value) return result;
}
}
return value;
};
return JSON.stringify(obj, replacer, space);
}
matchPath(key, path) {
if (typeof path === 'string') return key === path;
if (path instanceof RegExp) return path.test(key);
if (typeof path === 'function') return path(key);
return false;
}
}
// 使用示例
const data = {
id: 1001,
username: 'zhangsan',
password: 'secret123',
email: 'zhangsan@example.com',
phone: '13800138000',
profile: {
age: 28,
salary: 25000,
},
createdAt: new Date(),
logs: ['login', 'update', 'logout'],
};
// 链式配置序列化规则
const result = SelectiveStringify.create()
.exclude('password')
.mask('phone', (phone) => phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2'))
.transform('email', (email) => email.toLowerCase())
.when(
'salary',
(value, ctx) => ctx.userRole === 'admin',
(value) => value,
() => '机密'
)
.transform('createdAt', (date) => date.toISOString())
.stringify(data, { userRole: 'user' }, 2);
console.log(result);Replacer 参数详解
1. 函数形式的 Replacer
const data = {
name: '测试',
password: '123456',
email: 'test@example.com',
age: 25,
salary: 50000,
};
// 过滤敏感信息
const safeStringify = JSON.stringify(data, (key, value) => {
if (key === 'password') return undefined;
if (key === 'salary') return '***';
return value;
});
console.log(safeStringify);
// 输出: {"name":"测试","email":"test@example.com","age":25,"salary":"***"}2. 数组形式的 Replacer
const user = {
id: 1,
name: '张三',
password: 'secret',
email: 'zhangsan@example.com',
phone: '13800138000',
address: '北京市朝阳区',
};
// 只序列化指定的属性
const publicInfo = JSON.stringify(user, ['id', 'name', 'email']);
console.log(publicInfo);
// 输出: {"id":1,"name":"张三","email":"zhangsan@example.com"}3. 高级 Replacer 用法
const data = {
users: [
{ name: '用户1', score: 85.6789 },
{ name: '用户2', score: 92.1234 },
],
timestamp: Date.now(),
};
const customReplacer = (key, value) => {
// 数字保留两位小数
if (typeof value === 'number' && key === 'score') {
return Number(value.toFixed(2));
}
// 时间戳转换为可读格式
if (key === 'timestamp') {
return new Date(value).toISOString();
}
return value;
};
console.log(JSON.stringify(data, customReplacer, 2));Space 参数详解
Space 参数是 JSON.stringify 中控制输出格式的关键参数,合理使用可以大大提升开发效率和代码可读性。
🎯 核心功能概述
Space 参数主要用于:
- 调试输出 - 让 JSON 数据更易读,便于调试
- 文档生成 - 创建格式化的示例数据
- 配置文件 - 生成人类友好的配置文件
- API 文档 - 展示结构化的响应示例
1. 数字格式化 - 标准缩进
const complexData = {
user: {
id: 1001,
profile: {
name: '张三',
age: 28,
skills: ['JavaScript', 'Python', 'Go'],
address: {
country: '中国',
city: '北京',
district: '朝阳区',
},
},
preferences: {
theme: 'dark',
language: 'zh-CN',
notifications: {
email: true,
push: false,
sms: true,
},
},
},
metadata: {
createdAt: '2024-01-01T00:00:00.000Z',
version: '1.2.0',
features: ['auth', 'analytics', 'reporting'],
},
};
// 不同缩进级别的对比
console.log('无缩进(压缩):');
console.log(JSON.stringify(complexData));
console.log('\n缩进 2 空格(推荐):');
console.log(JSON.stringify(complexData, null, 2));
console.log('\n缩进 4 空格(详细):');
console.log(JSON.stringify(complexData, null, 4));
console.log('\n缩进 1 空格(紧凑):');
console.log(JSON.stringify(complexData, null, 1));2. 字符串格式化 - 创意缩进
const apiResponse = {
status: 'success',
data: {
users: [
{ id: 1, name: '用户A', active: true },
{ id: 2, name: '用户B', active: false },
],
pagination: {
page: 1,
limit: 10,
total: 2,
},
},
timestamp: '2025-09-15T10:30:00.000Z',
};
// 使用不同字符作为缩进
console.log('使用箭头缩进(适合文档展示):');
console.log(JSON.stringify(apiResponse, null, '→ '));
console.log('\n使用点号缩进(适合层级展示):');
console.log(JSON.stringify(apiResponse, null, '··'));
console.log('\n使用竖线缩进(适合树状结构):');
console.log(JSON.stringify(apiResponse, null, '│ '));
console.log('\n使用制表符缩进(适合代码编辑器):');
console.log(JSON.stringify(apiResponse, null, '\t'));3. 智能美化工具类
class JSONFormatter {
constructor(options = {}) {
this.options = {
maxLineLength: options.maxLineLength || 80,
arrayThreshold: options.arrayThreshold || 5,
objectThreshold: options.objectThreshold || 3,
colorOutput: options.colorOutput || false,
showDataTypes: options.showDataTypes || false,
...options,
};
}
format(data, space = 2) {
// 智能判断是否需要格式化
const stringified = JSON.stringify(data);
if (
stringified.length <= this.options.maxLineLength &&
!this.hasComplexStructure(data)
) {
return stringified; // 简单数据保持单行
}
return JSON.stringify(data, this.createSmartReplacer(), space);
}
createSmartReplacer() {
return (key, value) => {
// 数组智能格式化
if (Array.isArray(value)) {
if (
value.length <= this.options.arrayThreshold &&
value.every((item) => typeof item !== 'object')
) {
// 简单数组保持单行
return value;
}
}
// 对象智能格式化
if (value && typeof value === 'object' && !Array.isArray(value)) {
const keys = Object.keys(value);
if (
keys.length <= this.options.objectThreshold &&
keys.every((k) => typeof value[k] !== 'object')
) {
// 简单对象可以考虑紧凑格式
}
}
// 数据类型注释(调试模式)
if (this.options.showDataTypes && value !== null) {
if (typeof value === 'string' && key !== '') {
return `${value} /* string */`;
}
if (typeof value === 'number' && key !== '') {
return `${value} /* number */`;
}
}
return value;
};
}
hasComplexStructure(data) {
const str = JSON.stringify(data);
return str.includes('{') || str.includes('[') || str.includes('","');
}
// 调试专用格式化
debug(data, label = 'Debug Output') {
console.log(`\n=== ${label} ===`);
console.log(this.format(data, 2));
console.log(`=== End ${label} ===\n`);
return data; // 支持链式调用
}
// 生成文档示例
generateDocExample(data, description = '') {
const formatted = this.format(data, 2);
return `${
description ? `// ${description}\n` : ''
}const example = ${formatted};`;
}
// 彩色输出(终端环境)
colorFormat(data) {
if (!this.options.colorOutput) {
return this.format(data);
}
const colors = {
reset: '\x1b[0m',
bright: '\x1b[1m',
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m',
};
return JSON.stringify(
data,
(key, value) => {
if (typeof value === 'string')
return `${colors.green}${value}${colors.reset}`;
if (typeof value === 'number')
return `${colors.yellow}${value}${colors.reset}`;
if (typeof value === 'boolean')
return `${colors.blue}${value}${colors.reset}`;
if (value === null) return `${colors.red}${value}${colors.reset}`;
return value;
},
2
);
}
}
// 使用示例
const formatter = new JSONFormatter({
maxLineLength: 60,
arrayThreshold: 3,
showDataTypes: true,
colorOutput: true,
});
const testData = {
simple: { a: 1, b: 2 },
complex: {
nested: {
deep: {
value: 'test',
},
},
},
array: [1, 2, 3, 4, 5, 6],
simpleArray: ['a', 'b'],
};
console.log('智能格式化:');
console.log(formatter.format(testData));
console.log('\n调试输出:');
formatter.debug(testData, 'Test Data Structure');
console.log('\n文档示例:');
console.log(formatter.generateDocExample(testData.simple, '简单对象示例'));特殊值处理
1. undefined、函数和 Symbol
const obj = {
name: '测试',
age: undefined,
method: function () {
return 'hello';
},
symbol: Symbol('test'),
valid: true,
};
console.log(JSON.stringify(obj));
// 输出: {"name":"测试","valid":true}
// undefined、函数和 Symbol 会被忽略2. 数组中的特殊值
const arr = [1, undefined, function () {}, Symbol('test'), null, true];
console.log(JSON.stringify(arr));
// 输出: [1,null,null,null,null,true]
// 数组中的 undefined、函数、Symbol 会被转换为 null3. NaN 和 Infinity
const data = {
notANumber: NaN,
infinity: Infinity,
negativeInfinity: -Infinity,
validNumber: 42,
};
console.log(JSON.stringify(data));
// 输出: {"notANumber":null,"infinity":null,"negativeInfinity":null,"validNumber":42}循环引用处理
1. 检测和处理循环引用
const obj = { name: 'test' };
obj.self = obj; // 创建循环引用
// 这会抛出错误
try {
JSON.stringify(obj);
} catch (error) {
console.log(error.message); // "Converting circular structure to JSON"
}
// 安全的循环引用处理
function safeStringify(obj) {
const seen = new WeakSet();
return JSON.stringify(obj, (key, value) => {
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) {
return '[Circular]';
}
seen.add(value);
}
return value;
});
}
console.log(safeStringify(obj));
// 输出: {"name":"test","self":"[Circular]"}2. 复杂循环引用处理
class CircularHandler {
constructor() {
this.pathStack = [];
this.seen = new WeakMap();
}
stringify(obj) {
this.pathStack = [];
this.seen = new WeakMap();
return JSON.stringify(obj, (key, value) => {
return this.handleValue(key, value);
});
}
handleValue(key, value) {
if (typeof value !== 'object' || value === null) {
return value;
}
// 检查循环引用
if (this.seen.has(value)) {
const path = this.seen.get(value);
return `[Circular: ${path}]`;
}
// 记录当前路径
const currentPath =
this.pathStack.length === 0
? 'root'
: this.pathStack.join('.') + (key ? `.${key}` : '');
this.seen.set(value, currentPath);
// 添加到路径栈
if (key) this.pathStack.push(key);
// 处理完成后从路径栈移除
setTimeout(() => {
if (key) this.pathStack.pop();
}, 0);
return value;
}
}
// 使用示例
const a = { name: 'A' };
const b = { name: 'B', ref: a };
a.ref = b; // 创建循环引用
const handler = new CircularHandler();
console.log(handler.stringify({ root: a }));性能优化
1. 大数据序列化优化
class OptimizedStringify {
constructor() {
this.cache = new Map();
this.cacheSize = 1000;
}
stringify(obj, options = {}) {
const { useCache = true, chunkSize = 10000 } = options;
// 缓存策略
if (useCache) {
const key = this.generateCacheKey(obj);
if (this.cache.has(key)) {
return this.cache.get(key);
}
}
// 分块处理大数组
if (Array.isArray(obj) && obj.length > chunkSize) {
return this.stringifyLargeArray(obj, chunkSize);
}
const result = JSON.stringify(obj);
// 缓存结果
if (useCache && result.length < 100000) {
// 只缓存小于100KB的结果
this.addToCache(this.generateCacheKey(obj), result);
}
return result;
}
stringifyLargeArray(arr, chunkSize) {
const chunks = [];
for (let i = 0; i < arr.length; i += chunkSize) {
const chunk = arr.slice(i, i + chunkSize);
chunks.push(JSON.stringify(chunk).slice(1, -1)); // 移除数组括号
}
return '[' + chunks.join(',') + ']';
}
generateCacheKey(obj) {
// 简单的缓存键生成
if (typeof obj === 'object' && obj !== null) {
const keys = Object.keys(obj).sort();
return keys.join(',') + '_' + typeof obj;
}
return String(obj);
}
addToCache(key, value) {
if (this.cache.size >= this.cacheSize) {
// 移除最老的缓存项
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, value);
}
clearCache() {
this.cache.clear();
}
}
// 使用示例
const optimizer = new OptimizedStringify();
const largeArray = new Array(50000)
.fill(0)
.map((_, i) => ({ id: i, value: `item${i}` }));
console.time('优化版序列化');
const result1 = optimizer.stringify(largeArray);
console.timeEnd('优化版序列化');
console.time('标准序列化');
const result2 = JSON.stringify(largeArray);
console.timeEnd('标准序列化');
console.log('结果一致:', result1 === result2);2. 性能监控
class PerformanceMonitor {
static monitor(obj, label = 'JSON.stringify') {
const startTime = performance.now();
const startMemory = this.getMemoryUsage();
const result = JSON.stringify(obj);
const endTime = performance.now();
const endMemory = this.getMemoryUsage();
const metrics = {
label,
duration: (endTime - startTime).toFixed(2) + 'ms',
outputSize: result.length,
memoryDelta: endMemory - startMemory,
throughput:
((result.length / (endTime - startTime)) * 1000).toFixed(0) +
' chars/s',
};
console.table(metrics);
return result;
}
static getMemoryUsage() {
if (typeof process !== 'undefined' && process.memoryUsage) {
return process.memoryUsage().heapUsed;
}
return 0; // 浏览器环境
}
static benchmark(obj, iterations = 100) {
const times = [];
for (let i = 0; i < iterations; i++) {
const start = performance.now();
JSON.stringify(obj);
const end = performance.now();
times.push(end - start);
}
const avgTime = times.reduce((a, b) => a + b) / times.length;
const minTime = Math.min(...times);
const maxTime = Math.max(...times);
console.log(`平均时间: ${avgTime.toFixed(2)}ms`);
console.log(`最短时间: ${minTime.toFixed(2)}ms`);
console.log(`最长时间: ${maxTime.toFixed(2)}ms`);
return { avgTime, minTime, maxTime };
}
}
// 使用示例
const testData = {
users: new Array(1000).fill(0).map((_, i) => ({
id: i,
name: `用户${i}`,
data: new Array(100).fill(Math.random()),
})),
};
PerformanceMonitor.monitor(testData, '大数据测试');
PerformanceMonitor.benchmark(testData, 50);实际应用场景
1. API 数据传输
class APISerializer {
constructor() {
this.compressionEnabled = true;
this.maxResponseSize = 1024 * 1024; // 1MB
}
serializeResponse(data, version = 'v1') {
const serializers = {
v1: this.serializeV1.bind(this),
v2: this.serializeV2.bind(this),
};
const serializer = serializers[version] || serializers.v1;
let result = serializer(data);
// 检查响应大小
if (result.length > this.maxResponseSize) {
console.warn('响应数据过大,考虑分页或数据压缩');
result = this.compressResponse(result);
}
return result;
}
serializeV1(data) {
return JSON.stringify({
status: 'success',
data: data,
timestamp: new Date().toISOString(),
});
}
serializeV2(data) {
return JSON.stringify(
{
success: true,
result: data,
meta: {
timestamp: Date.now(),
version: 'v2',
},
},
null,
this.compressionEnabled ? 0 : 2
);
}
compressResponse(response) {
// 简单的压缩策略:移除不必要的空白
return response.replace(/\s+/g, ' ').trim();
}
}
// 使用示例
const apiSerializer = new APISerializer();
const userData = { id: 1, name: '张三', email: 'zhangsan@example.com' };
console.log('API v1 响应:');
console.log(apiSerializer.serializeResponse(userData, 'v1'));
console.log('\nAPI v2 响应:');
console.log(apiSerializer.serializeResponse(userData, 'v2'));2. 配置文件生成
class ConfigGenerator {
constructor() {
this.templates = new Map();
this.validators = new Map();
}
registerTemplate(name, template, validator = null) {
this.templates.set(name, template);
if (validator) {
this.validators.set(name, validator);
}
return this;
}
generateConfig(templateName, values = {}) {
const template = this.templates.get(templateName);
if (!template) {
throw new Error(`Template '${templateName}' not found`);
}
const config = this.mergeValues(template, values);
// 验证配置
const validator = this.validators.get(templateName);
if (validator && !validator(config)) {
throw new Error(`Configuration validation failed for '${templateName}'`);
}
return this.formatConfig(config, templateName);
}
mergeValues(template, values) {
const result = JSON.parse(JSON.stringify(template)); // 深拷贝
return this.deepMerge(result, values);
}
deepMerge(target, source) {
for (const key in source) {
if (
source[key] &&
typeof source[key] === 'object' &&
!Array.isArray(source[key])
) {
if (!target[key]) target[key] = {};
this.deepMerge(target[key], source[key]);
} else {
target[key] = source[key];
}
}
return target;
}
formatConfig(config, templateName) {
const formatted = JSON.stringify(config, null, 2);
const header = `// ${templateName} 配置文件\n// 生成时间: ${new Date().toISOString()}\n\n`;
return header + formatted;
}
}
// 注册配置模板
const configGen = new ConfigGenerator();
configGen.registerTemplate(
'database',
{
host: 'localhost',
port: 5432,
database: 'myapp',
username: 'user',
password: 'password',
pool: {
min: 2,
max: 10,
idle: 30000,
},
ssl: false,
},
(config) => {
return config.port > 0 && config.pool.max > config.pool.min;
}
);
configGen.registerTemplate('redis', {
host: 'localhost',
port: 6379,
db: 0,
keyPrefix: 'myapp:',
ttl: 3600,
});
// 生成配置
console.log('数据库配置:');
console.log(
configGen.generateConfig('database', {
host: 'prod-db.example.com',
database: 'production_db',
pool: { max: 20 },
})
);
console.log('\nRedis配置:');
console.log(
configGen.generateConfig('redis', {
host: 'redis.example.com',
keyPrefix: 'prod:',
})
);总结
这份基础与进阶指南涵盖了 JSON.stringify 的核心功能和实用技巧:
🎯 掌握重点
- 基础应用 - 理解语法、参数和基本用法
- 选择性序列化 - 掌握数据过滤和转换技巧
- 格式化输出 - 合理使用 space 参数提升可读性
- 特殊值处理 - 了解各种数据类型的序列化行为
- 循环引用 - 学会检测和处理循环引用问题
- 性能优化 - 应用缓存和分块等优化策略
- 实际应用 - 在 API、配置等场景中灵活运用
🚀 下一步学习
接下来可以继续学习:
- 与其他序列化方法的比较
- 错误处理与调试技巧
- 安全性考虑与防护措施
- 企业级最佳实践
- 开发工具与生态系统
通过掌握这些基础与进阶知识,你将能够在实际项目中高效、安全地使用 JSON.stringify!
到此这篇关于JSON.stringify 基础与进阶用法指南的文章就介绍到这了,更多相关JSON.stringify 用法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
