Improvement of JSON.stringify()
Improvements to JSON.stringify() in ECMAScript 10
ECMAScript 10 (ES2019) introduced two significant improvements to JSON.stringify()
: resolving precision loss with large numbers and optimizing Unicode escaping. These changes make JSON serialization more reliable, especially when handling special characters and large numbers.
Resolving Precision Loss with Large Numbers
Prior to ES10, JSON.stringify()
would throw an error when processing BigInt
types or numbers exceeding Number.MAX_SAFE_INTEGER
. ES10 addressed this by introducing extended support for the "toJSON" method and enhancements to custom replacer functions.
const bigObj = {
regularNumber: 42,
bigNumber: BigInt(9007199254740993) // Exceeds Number.MAX_SAFE_INTEGER
};
// Pre-ES10 would throw a TypeError
JSON.stringify(bigObj, (key, value) =>
typeof value === 'bigint' ? value.toString() : value
);
// Output: '{"regularNumber":42,"bigNumber":"9007199254740993"}'
The new specification explicitly allows handling large numbers via replacer functions and increases flexibility for return types from toJSON()
:
class CustomBigInt {
constructor(value) {
this.value = BigInt(value);
}
toJSON() {
return { type: 'bigint', value: this.value.toString() };
}
}
const data = {
id: new CustomBigInt('12345678901234567890')
};
JSON.stringify(data);
// Output: '{"id":{"type":"bigint","value":"12345678901234567890"}}'
Unified Handling of Unicode Escape Sequences
ES10 mandates that JSON.stringify()
use standardized Unicode escape sequences for surrogate pairs and special characters. Previously, different engines might output varying escape formats:
const emoji = '😊';
// Pre-ES10 might output '"\uD83D\uDE0A"' or '"\u{1F60A}"'
JSON.stringify(emoji);
// Post-ES10 standardizes output to: '"\\uD83D\\uDE0A"'
This improvement ensures cross-engine consistency, particularly for:
- Characters outside the Basic Multilingual Plane (BMP) (code points > 0xFFFF)
- Control characters (0x00-0x1F)
- Quotes (0x22) and backslashes (0x5C)
Optimization of Circular Reference Detection
Though not a new feature, ES10 specifies that engines must use a deterministic algorithm for circular reference detection. The following example demonstrates more predictable behavior:
const circularObj = { name: "Circular Object" };
circularObj.self = circularObj;
// Engines now throw a TypeError with consistent formatting
try {
JSON.stringify(circularObj);
} catch (e) {
console.log(e.message); // "Converting circular structure to JSON"
}
Strict Ordering for Replacer Arrays
When using an array as the replacer parameter, ES10 enforces strict property processing in the order of array elements:
const obj = { b: 2, a: 1, c: 3 };
// Pre-ES10 might output alphabetically
JSON.stringify(obj, ['a', 'b', 'c']);
// Now strictly outputs: '{"a":1,"b":2,"c":3}'
Practical Use Cases
Use Case 1: API Response Handling
async function fetchFinancialData() {
const response = await fetch('/api/large-numbers');
const data = await response.json();
// Safely handle large numbers
return JSON.parse(JSON.stringify(data, (key, val) =>
val?.type === 'bigint' ? BigInt(val.value) : val
));
}
Use Case 2: Logging
const transaction = {
id: BigInt('202308011234567890'),
amount: '¥1000000',
timestamp: new Date()
};
const logEntry = JSON.stringify(transaction, (key, value) => {
if (value instanceof Date) return value.toISOString();
if (typeof value === 'bigint') return `#BIGINT${value.toString()}`;
return value;
});
console.log(logEntry);
// Output: '{"id":"#BIGINT202308011234567890","amount":"¥1000000","timestamp":"2023-08-01T00:00:00.000Z"}'
Performance Considerations
While the new features enhance functionality, note the following:
- Using a replacer function slows serialization by 30-50%
- String conversion of large numbers incurs additional memory overhead
- Circular reference detection for deeply nested objects now uses a stricter algorithm
// Performance comparison test
const largeObj = /* Object with 10,000 properties */;
console.time('default');
JSON.stringify(largeObj);
console.timeEnd('default'); // ~120ms
console.time('with replacer');
JSON.stringify(largeObj, (k, v) => v);
console.timeEnd('with replacer'); // ~180ms
Interaction with Other Features
ES10’s JSON.stringify()
improvements work particularly well with:
- BigInt type: Serialization via replacer
- Optional chaining: Safe access to potentially missing properties
- Nullish coalescing: More convenient default value handling
const config = {
transactionLimit: BigInt(1e18),
expiryDate: null
};
const serialized = JSON.stringify(config, (key, value) => {
return value ?? 'Not set'; // Nullish coalescing
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn