返回

JSON.stringify() 揭秘:亲自动手打造 JSON 序列化引擎

前端

在 JavaScript 的生态圈中,JSON.stringify() 方法扮演着至关重要的角色,负责将 JavaScript 对象优雅地转换为 JSON 字符串。然而,这个看似简单的过程背后隐藏着令人着迷的算法和技术细节。在这篇深入的文章中,我们将踏上一段探索之旅,一步一步剖析 JSON.stringify() 方法的内在原理,亲自动手打造一个属于自己的 JSON 序列化引擎。

构建 JSON 序列化引擎的奥秘

JSON.stringify() 方法的工作原理建立在两个核心概念之上:

  • 递归遍历: 方法通过深度优先遍历 JavaScript 对象,逐层解析其键值对。
  • 值类型处理: 不同类型的值(字符串、数字、布尔值等)需要遵循特定的规则进行序列化。

剖析 JSON.stringify() 的算法

1. 入口点:

JSON.stringify(obj, replacer, space)
  • obj:要序列化的 JavaScript 对象。
  • replacer(可选):用于自定义序列化的函数。
  • space(可选):用于美化输出 JSON 字符串的空格数。

2. 值类型处理:

  • 字符串: 使用双引号包裹并转义特殊字符。
  • 数字、布尔值、null: 直接输出值本身。
  • 数组: 使用方括号包裹并递归调用 JSON.stringify()
  • 对象: 使用大括号包裹并递归调用 JSON.stringify(),遵循键值对的顺序。
  • 未定义、函数、Symbol: 转换为 null

3. 循环引用处理:

为防止无限递归,在遍历过程中维护一个包含已序列化的对象引用的数组。如果遇到一个循环引用,则替换为 null

4. 字符串化过程:

  • 将所有值序列化为字符串。
  • 对于对象,将键和值按顺序连接为字符串。
  • 对于数组,将元素连接为字符串,并用逗号分隔。
  • 根据 space 参数,添加空格以美化输出。

手动实现 JSON.stringify()

1. 初始化:

function stringify(obj) {
  let output = '';
  const seen = [];

  return serialize(obj, seen, output);
}

2. 递归序列化函数:

function serialize(obj, seen, output) {
  // 处理值类型
  if (typeof obj === 'string') {
    // 字符串转义
    return '"' + escape(obj) + '"';
  } else if (typeof obj === 'number' || typeof obj === 'boolean' || obj === null) {
    // 直接输出值
    return obj.toString();
  } else if (Array.isArray(obj)) {
    // 处理数组
    return '[' + obj.map(val => serialize(val, seen, output)).join(',') + ']';
  } else if (typeof obj === 'object') {
    // 处理对象
    if (seen.includes(obj)) {
      // 循环引用
      return 'null';
    }
    seen.push(obj);
    const keys = Object.keys(obj);
    return '{' + keys.map(key => serialize(key, seen, output) + ':' + serialize(obj[key], seen, output)).join(',') + '}';
  } else {
    // 未定义、函数、Symbol
    return 'null';
  }
}

3. 字符串转义:

function escape(str) {
  return str.replace(/[\u0000-\u001f\"\\\//g, char => {
    switch (char) {
      case '\b': return '\\b';
      case '\f': return '\\f';
      case '\n': return '\\n';
      case '\r': return '\\r';
      case '\t': return '\\t';
      case '\'': return '\\\'';
      case '"': return '\\"';
      case '\\': return '\\\\';
      case '/': return '\\/';
      default: return '\\u' + char.charCodeAt(0).toString(16).padStart(4, '0');
    }
  });
}

通过遵循这些步骤,你可以亲手构建一个功能完备的 JSON 序列化引擎,它可以将任何 JavaScript 对象转换为一个有效的 JSON 字符串。