阿里云主机折上折
  • 微信号
Current Site:Index > Improvement of JSON.stringify()

Improvement of JSON.stringify()

Author:Chuan Chen 阅读数:40910人阅读 分类: JavaScript

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:

  1. Using a replacer function slows serialization by 30-50%
  2. String conversion of large numbers incurs additional memory overhead
  3. 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

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.