JSON.stringify 基礎(chǔ)與進(jìn)階用法完全攻略
JSON.stringify 基礎(chǔ)與進(jìn)階用法指南
關(guān)鍵特性概覽
?? 核心能力
JSON.stringify 是 JavaScript 內(nèi)置的序列化方法,具有以下關(guān)鍵特性:
1.通用序列化支持
- ? 支持所有 JSON 兼容的數(shù)據(jù)類型
- ? 自動處理嵌套對象和數(shù)組
- ? 保持?jǐn)?shù)據(jù)結(jié)構(gòu)的完整性
- ? 自動忽略 undefined、Symbol 和函數(shù)類型的屬性
- ? 只序列化對象自身的可枚舉屬性
- ? 日期對象還沒轉(zhuǎn)化為 ISO 格式字符串
- ? 循環(huán)引用會拋出錯(cuò)誤
// 支持復(fù)雜數(shù)據(jù)結(jié)構(gòu)
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.靈活的數(shù)據(jù)轉(zhuǎn)換
- ?? Replacer 函數(shù)自定義轉(zhuǎn)換邏輯
- ?? 白名單模式精確控制輸出
- ?? toJSON 方法實(shí)現(xiàn)對象級別控制
// 多種轉(zhuǎn)換方式
const data = { name: '測試', password: 'secret', age: 25 };
// 方式1:函數(shù)過濾
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.智能格式化輸出
- ?? 支持縮進(jìn)美化
- ?? 自定義縮進(jìn)字符
- ?? 壓縮與可讀性平衡
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
}
}
*/
// 自定義縮進(jìn)
JSON.stringify(obj, null, '→');
/*
{
→"a": 1,
→"b": {
→→"c": 2
→}
}
*/4.安全性保障
- ??? 自動過濾不安全的數(shù)據(jù)類型
- ??? 防止代碼注入
- ??? 循環(huán)引用檢測(需自定義處理)
const unsafeData = {
name: '用戶',
method: function () {
return 'danger';
}, // 被忽略
symbol: Symbol('test'), // 被忽略
undef: undefined, // 被忽略
safe: 'normal string', // 保留
};
JSON.stringify(unsafeData);
// 輸出: {"name":"用戶","safe":"normal string"}?? 核心優(yōu)勢
| 特性 | 描述 | 應(yīng)用場景 |
|---|---|---|
| 原生支持 | 瀏覽器和 Node.js 內(nèi)置 | 無需額外依賴 |
| 高性能 | C++ 底層實(shí)現(xiàn),速度快 | 大數(shù)據(jù)序列化 |
| 標(biāo)準(zhǔn)兼容 | 嚴(yán)格遵循 JSON 規(guī)范 | 跨平臺數(shù)據(jù)交換 |
| 靈活配置 | 多參數(shù)精確控制 | 復(fù)雜業(yè)務(wù)需求 |
| 錯(cuò)誤處理 | 明確的異常機(jī)制 | 生產(chǎn)環(huán)境穩(wěn)定性 |
? 性能特點(diǎn)
// 性能基準(zhǔn)測試示例
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(`數(shù)據(jù)大小: ${result.length} 字符`);
console.log(
`壓縮率: ${(
(result.length / JSON.stringify(testData, null, 2).length) *
100
).toFixed(1)}%`
);
}
benchmarkStringify();
// 典型輸出:
// JSON.stringify: 15.234ms
// 數(shù)據(jù)大小: 889123 字符
// 壓縮率: 45.2%?? 兼容性矩陣
| 環(huán)境 | 版本支持 | 特性完整度 | 備注 |
|---|---|---|---|
| Chrome | 4+ | 100% | 完全支持 |
| Firefox | 3.5+ | 100% | 完全支持 |
| Safari | 4+ | 100% | 完全支持 |
| IE | 8+ | 100% | 原生支持 |
| Node.js | 0.1+ | 100% | 服務(wù)端支持 |
| React Native | 全版本 | 100% | 移動端支持 |
??? 擴(kuò)展能力
// 擴(kuò)展 JSON.stringify 功能示例
class EnhancedJSON {
static stringify(obj, options = {}) {
const {
// 基礎(chǔ)選項(xiàng)
replacer = null,
space = null,
// 擴(kuò)展選項(xiàng)
maxDepth = Infinity,
dateFormat = 'iso', // 'iso' | 'timestamp' | 'locale'
errorHandler = 'throw', // 'throw' | 'skip' | 'placeholder'
bigintSupport = false, // 是否支持 BigInt
functionSupport = false, // 是否保留函數(shù)
// 安全選項(xiàng)
sensitiveKeys = ['password', 'token', 'secret'],
maxSize = 1024 * 1024, // 最大 1MB
// 性能選項(xiàng)
cache = false, // 是否啟用緩存
stream = false, // 是否流式處理
} = options;
// 實(shí)現(xiàn)增強(qiáng)的序列化邏輯...
return this._enhancedStringify(obj, {
replacer,
space,
maxDepth,
dateFormat,
errorHandler,
bigintSupport,
functionSupport,
sensitiveKeys,
maxSize,
cache,
stream,
});
}
static _enhancedStringify(obj, options) {
// 詳細(xì)實(shí)現(xiàn)邏輯...
// 這里可以添加各種增強(qiáng)功能
}
}基礎(chǔ)語法
JSON.stringify(value[, replacer[, space]])
參數(shù)說明:
value: 要序列化的值replacer(可選): 轉(zhuǎn)換器函數(shù)或數(shù)組,用于過濾和轉(zhuǎn)換結(jié)果space(可選): 用于美化輸出的空白字符
基礎(chǔ)用法
1. 簡單對象序列化
const obj = {
name: '張三',
age: 25,
city: '北京',
};
console.log(JSON.stringify(obj));
// 輸出: {"name":"張三","age":25,"city":"北京"}2. 數(shù)組序列化
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"}進(jìn)階用法
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(); // 返回時(shí)間戳
};
console.log(JSON.stringify(dateObj));
// 輸出: {"created":1726397400000,"updated":1704067200000}選擇性序列化
選擇性序列化是 JSON.stringify 最強(qiáng)大的功能之一,允許我們精確控制哪些數(shù)據(jù)被序列化,如何轉(zhuǎn)換數(shù)據(jù),以及輸出格式。
?? 核心概念
選擇性序列化主要通過以下三種方式實(shí)現(xiàn):
- Replacer 函數(shù) - 逐個(gè)處理每個(gè)鍵值對
- Replacer 數(shù)組 - 白名單模式指定屬性
- toJSON 方法 - 對象級別的自定義序列化
1. 基于函數(shù)的選擇性序列化
1.1 基礎(chǔ)過濾
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',
},
};
// 基礎(chǔ)敏感信息過濾
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 數(shù)據(jù)脫敏
const sensitiveData = {
name: '張三',
idCard: '110101199001011234',
phone: '13800138000',
email: 'zhangsan@example.com',
bankCard: '6222021234567890123',
salary: 15000,
};
// 數(shù)據(jù)脫敏處理
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':
// 手機(jī)號脫敏:顯示前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':
// 薪資脫敏:轉(zhuǎn)為范圍
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, // 內(nèi)部成本,不對外
inventory: 150,
status: 'active',
internal: {
supplier: 'Apple Inc',
margin: 43.7, // 利潤率,敏感信息
notes: 'Q4 熱銷產(chǎn)品',
},
public: {
description: '最新款智能手機(jī)',
features: ['A17 芯片', '48MP 相機(jī)', '128GB 存儲'],
},
};
// 根據(jù)用戶權(quán)限選擇性序列化
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') {
// 客戶只能看到庫存狀態(tài),不能看到具體數(shù)量
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. 基于數(shù)組的選擇性序列化
2.1 白名單模式
const fullUserProfile = {
// 基本信息
id: 1001,
username: 'zhangsan',
email: 'zhangsan@example.com',
// 敏感信息
password: 'secret123',
ssn: '123-45-6789',
// 個(gè)人信息
firstName: '三',
lastName: '張',
age: 28,
// 系統(tǒng)信息
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'],
// 個(gè)人資料編輯
profile: [
'id',
'username',
'email',
'firstName',
'lastName',
'age',
'preferences',
],
// 系統(tǒng)管理
admin: ['id', 'username', 'email', 'isActive', 'createdAt', 'updatedAt'],
// API 響應(yīng)
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 動態(tài)白名單
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: '專業(yè)級筆記本電腦',
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'];
}
// 設(shè)置序列化上下文
setContext(context) {
this._context = context;
return this;
}
toJSON() {
const result = {};
const context = this._context || {};
for (const [key, value] of Object.entries(this)) {
// 跳過內(nèi)部字段
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('默認(rèn)序列化:', 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;
}
// 設(shè)置當(dāng)前版本
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)
);
});??? 實(shí)用工具類
// 選擇性序列化工具類
class SelectiveStringify {
static create() {
return new SelectiveStringify();
}
constructor() {
this.rules = [];
this.globalOptions = {};
}
// 添加字段規(guī)則
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;
}
// 轉(zhuǎn)換字段
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;
}
// 執(zhí)行序列化
stringify(obj, context = {}, space = null) {
const replacer = (key, value) => {
if (key === '') return value;
// 包含字段檢查
if (this.includeOnly && !this.includeOnly.has(key)) {
return undefined;
}
// 應(yīng)用字段規(guī)則
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'],
};
// 鏈?zhǔn)脚渲眯蛄谢?guī)則
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,
() => '機(jī)密'
)
.transform('createdAt', (date) => date.toISOString())
.stringify(data, { userRole: 'user' }, 2);
console.log(result);Replacer 參數(shù)詳解
1. 函數(shù)形式的 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. 數(shù)組形式的 Replacer
const user = {
id: 1,
name: '張三',
password: 'secret',
email: 'zhangsan@example.com',
phone: '13800138000',
address: '北京市朝陽區(qū)',
};
// 只序列化指定的屬性
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) => {
// 數(shù)字保留兩位小數(shù)
if (typeof value === 'number' && key === 'score') {
return Number(value.toFixed(2));
}
// 時(shí)間戳轉(zhuǎn)換為可讀格式
if (key === 'timestamp') {
return new Date(value).toISOString();
}
return value;
};
console.log(JSON.stringify(data, customReplacer, 2));Space 參數(shù)詳解
Space 參數(shù)是 JSON.stringify 中控制輸出格式的關(guān)鍵參數(shù),合理使用可以大大提升開發(fā)效率和代碼可讀性。
?? 核心功能概述
Space 參數(shù)主要用于:
- 調(diào)試輸出 - 讓 JSON 數(shù)據(jù)更易讀,便于調(diào)試
- 文檔生成 - 創(chuàng)建格式化的示例數(shù)據(jù)
- 配置文件 - 生成人類友好的配置文件
- API 文檔 - 展示結(jié)構(gòu)化的響應(yīng)示例
1. 數(shù)字格式化 - 標(biāo)準(zhǔn)縮進(jìn)
const complexData = {
user: {
id: 1001,
profile: {
name: '張三',
age: 28,
skills: ['JavaScript', 'Python', 'Go'],
address: {
country: '中國',
city: '北京',
district: '朝陽區(qū)',
},
},
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'],
},
};
// 不同縮進(jìn)級別的對比
console.log('無縮進(jìn)(壓縮):');
console.log(JSON.stringify(complexData));
console.log('\n縮進(jìn) 2 空格(推薦):');
console.log(JSON.stringify(complexData, null, 2));
console.log('\n縮進(jìn) 4 空格(詳細(xì)):');
console.log(JSON.stringify(complexData, null, 4));
console.log('\n縮進(jìn) 1 空格(緊湊):');
console.log(JSON.stringify(complexData, null, 1));2. 字符串格式化 - 創(chuàng)意縮進(jìn)
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',
};
// 使用不同字符作為縮進(jìn)
console.log('使用箭頭縮進(jìn)(適合文檔展示):');
console.log(JSON.stringify(apiResponse, null, '→ '));
console.log('\n使用點(diǎn)號縮進(jìn)(適合層級展示):');
console.log(JSON.stringify(apiResponse, null, '··'));
console.log('\n使用豎線縮進(jìn)(適合樹狀結(jié)構(gòu)):');
console.log(JSON.stringify(apiResponse, null, '│ '));
console.log('\n使用制表符縮進(jì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; // 簡單數(shù)據(jù)保持單行
}
return JSON.stringify(data, this.createSmartReplacer(), space);
}
createSmartReplacer() {
return (key, value) => {
// 數(shù)組智能格式化
if (Array.isArray(value)) {
if (
value.length <= this.options.arrayThreshold &&
value.every((item) => typeof item !== 'object')
) {
// 簡單數(shù)組保持單行
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')
) {
// 簡單對象可以考慮緊湊格式
}
}
// 數(shù)據(jù)類型注釋(調(diào)試模式)
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('","');
}
// 調(diào)試專用格式化
debug(data, label = 'Debug Output') {
console.log(`\n=== ${label} ===`);
console.log(this.format(data, 2));
console.log(`=== End ${label} ===\n`);
return data; // 支持鏈?zhǔn)秸{(diào)用
}
// 生成文檔示例
generateDocExample(data, description = '') {
const formatted = this.format(data, 2);
return `${
description ? `// ${description}\n` : ''
}const example = ${formatted};`;
}
// 彩色輸出(終端環(huán)境)
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調(diào)試輸出:');
formatter.debug(testData, 'Test Data Structure');
console.log('\n文檔示例:');
console.log(formatter.generateDocExample(testData.simple, '簡單對象示例'));特殊值處理
1. undefined、函數(shù)和 Symbol
const obj = {
name: '測試',
age: undefined,
method: function () {
return 'hello';
},
symbol: Symbol('test'),
valid: true,
};
console.log(JSON.stringify(obj));
// 輸出: {"name":"測試","valid":true}
// undefined、函數(shù)和 Symbol 會被忽略2. 數(shù)組中的特殊值
const arr = [1, undefined, function () {}, Symbol('test'), null, true];
console.log(JSON.stringify(arr));
// 輸出: [1,null,null,null,null,true]
// 數(shù)組中的 undefined、函數(shù)、Symbol 會被轉(zhuǎn)換為 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}循環(huán)引用處理
1. 檢測和處理循環(huán)引用
const obj = { name: 'test' };
obj.self = obj; // 創(chuàng)建循環(huán)引用
// 這會拋出錯(cuò)誤
try {
JSON.stringify(obj);
} catch (error) {
console.log(error.message); // "Converting circular structure to JSON"
}
// 安全的循環(huán)引用處理
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. 復(fù)雜循環(huán)引用處理
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;
}
// 檢查循環(huán)引用
if (this.seen.has(value)) {
const path = this.seen.get(value);
return `[Circular: ${path}]`;
}
// 記錄當(dāng)前路徑
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; // 創(chuàng)建循環(huán)引用
const handler = new CircularHandler();
console.log(handler.stringify({ root: a }));性能優(yōu)化
1. 大數(shù)據(jù)序列化優(yōu)化
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);
}
}
// 分塊處理大數(shù)組
if (Array.isArray(obj) && obj.length > chunkSize) {
return this.stringifyLargeArray(obj, chunkSize);
}
const result = JSON.stringify(obj);
// 緩存結(jié)果
if (useCache && result.length < 100000) {
// 只緩存小于100KB的結(jié)果
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)); // 移除數(shù)組括號
}
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) {
// 移除最老的緩存項(xiàng)
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('優(yōu)化版序列化');
const result1 = optimizer.stringify(largeArray);
console.timeEnd('優(yōu)化版序列化');
console.time('標(biāo)準(zhǔn)序列化');
const result2 = JSON.stringify(largeArray);
console.timeEnd('標(biāo)準(zhǔn)序列化');
console.log('結(jié)果一致:', result1 === result2);2. 性能監(jiān)控
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; // 瀏覽器環(huán)境
}
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(`平均時(shí)間: ${avgTime.toFixed(2)}ms`);
console.log(`最短時(shí)間: ${minTime.toFixed(2)}ms`);
console.log(`最長時(shí)間: ${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, '大數(shù)據(jù)測試');
PerformanceMonitor.benchmark(testData, 50);實(shí)際應(yīng)用場景
1. API 數(shù)據(jù)傳輸
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);
// 檢查響應(yīng)大小
if (result.length > this.maxResponseSize) {
console.warn('響應(yīng)數(shù)據(jù)過大,考慮分頁或數(shù)據(jù)壓縮');
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 響應(yīng):');
console.log(apiSerializer.serializeResponse(userData, 'v1'));
console.log('\nAPI v2 響應(yīng):');
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);
// 驗(yàn)證配置
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// 生成時(shí)間: ${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('數(shù)據(jù)庫配置:');
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:',
})
);總結(jié)
這份基礎(chǔ)與進(jìn)階指南涵蓋了 JSON.stringify 的核心功能和實(shí)用技巧:
?? 掌握重點(diǎn)
- 基礎(chǔ)應(yīng)用 - 理解語法、參數(shù)和基本用法
- 選擇性序列化 - 掌握數(shù)據(jù)過濾和轉(zhuǎn)換技巧
- 格式化輸出 - 合理使用 space 參數(shù)提升可讀性
- 特殊值處理 - 了解各種數(shù)據(jù)類型的序列化行為
- 循環(huán)引用 - 學(xué)會檢測和處理循環(huán)引用問題
- 性能優(yōu)化 - 應(yīng)用緩存和分塊等優(yōu)化策略
- 實(shí)際應(yīng)用 - 在 API、配置等場景中靈活運(yùn)用
?? 下一步學(xué)習(xí)
接下來可以繼續(xù)學(xué)習(xí):
- 與其他序列化方法的比較
- 錯(cuò)誤處理與調(diào)試技巧
- 安全性考慮與防護(hù)措施
- 企業(yè)級最佳實(shí)踐
- 開發(fā)工具與生態(tài)系統(tǒng)
通過掌握這些基礎(chǔ)與進(jìn)階知識,你將能夠在實(shí)際項(xiàng)目中高效、安全地使用 JSON.stringify!
到此這篇關(guān)于JSON.stringify 基礎(chǔ)與進(jìn)階用法指南的文章就介紹到這了,更多相關(guān)JSON.stringify 用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js拆分字符串并將分割的數(shù)據(jù)放到數(shù)組中的方法
這篇文章主要介紹了js拆分字符串并將分割的數(shù)據(jù)放到數(shù)組中的方法,涉及javascript中split方法及數(shù)組的操作技巧,需要的朋友可以參考下2015-05-05
用函數(shù)模板,寫一個(gè)簡單高效的 JSON 查詢器的方法介紹
本篇文章小編將為大家介紹,用函數(shù)模板,寫一個(gè)簡單高效的 JSON 查詢器的方法介紹,需要的朋友可以參考一下2013-04-04
javascript獲取鼠標(biāo)位置部分的實(shí)例代碼(兼容IE,FF)
這篇文章介紹了javascript獲取鼠標(biāo)位置部分的實(shí)例代碼,有需要的朋友可以參考一下2013-08-08

