JSON.stringify()(详细教程)

JSON.stringify() 是什么?它为什么这么重要?

在现代前端开发中,数据的传输和存储几乎都离不开 JSON 格式。而 JSON.stringify() 就是将 JavaScript 对象或数组转换成 JSON 字符串的核心工具。你可以把它想象成一个“数据打包机”——把复杂的对象结构,变成一串标准的、能被网络传输或存入本地的文本。

比如你在写一个 Vue 3.0 项目时,需要把用户表单数据发送给后端接口,这时候 JSON.stringify() 就派上用场了。它能帮你把 { name: "张三", age: 25 } 这样的对象,变成 {"name":"张三","age":25} 这种标准格式,让服务器能正确解析。

这个方法是 JavaScript 内置的,不需要引入额外库,使用起来非常方便。但它的功能远不止“简单转换”这么简单——它支持自定义序列化逻辑、处理特殊类型、甚至能避开循环引用问题。


基本用法:从对象到字符串的转换

我们先从最基础的用法开始。假设你有一个用户信息对象:

const user = {
  name: "李四",
  age: 30,
  isActive: true,
  hobbies: ["读书", "游泳", "编程"]
};

现在你想把这个对象变成字符串,以便保存到 localStorage 或发送到 API 接口。这时候就可以用 JSON.stringify()

const jsonString = JSON.stringify(user);
console.log(jsonString);
// 输出: {"name":"李四","age":30,"isActive":true,"hobbies":["读书","游泳","编程"]}

📌 关键点

  • JSON.stringify() 接收一个 JavaScript 值(对象、数组、字符串、数字等),返回一个 JSON 格式的字符串。
  • 不会改变原对象,而是返回一个新的字符串。
  • 如果传入的是 nullundefined,会返回 "null" 或直接报错(undefined 会忽略,但 null 会被保留)。

⚠️ 注意:JSON.stringify() 只能处理可序列化的数据类型。像函数、Symbol、undefined 等都无法被序列化。


处理复杂数据结构:数组与嵌套对象

JSON.stringify() 不仅能处理扁平对象,还能处理嵌套结构。比如一个包含多个用户的列表:

const users = [
  {
    id: 1,
    name: "王五",
    profile: {
      city: "北京",
      skills: ["JavaScript", "Vue 3.0", "Node.js"]
    }
  },
  {
    id: 2,
    name: "赵六",
    profile: {
      city: "上海",
      skills: ["Python", "Django", "Docker"]
    }
  }
];

const jsonUsers = JSON.stringify(users);
console.log(jsonUsers);
// 输出: [{"id":1,"name":"王五","profile":{"city":"北京","skills":["JavaScript","Vue 3.0","Node.js"]}}, {"id":2,"name":"赵六","profile":{"city":"上海","skills":["Python","Django","Docker"]}}]

这个结果非常清晰,结构完整,适合在前后端之间传递。

嵌套结构的“包装”比喻

你可以把 JSON.stringify() 想象成一个快递打包员:

  • 每个对象就像一个包裹,里面可能还有小盒子(嵌套对象)。
  • 打包员会一层层地把所有内容“贴上标签”,变成一串标准化的字符串,确保运输过程中不会被拆散。

第二个参数:replacer(序列化过滤器)

有时候你并不想把所有数据都传出去。比如用户对象里有敏感信息,如密码、token 等,就不该被序列化。

这时 JSON.stringify() 的第二个参数 replacer 就非常有用。它允许你指定哪些属性应该被包含或排除。

1. 使用数组过滤字段

const user = {
  name: "孙七",
  password: "123456",
  token: "abc123xyz",
  email: "sunqi@example.com",
  age: 28
};

// 只保留 name 和 email 字段
const filteredJson = JSON.stringify(user, ["name", "email"]);
console.log(filteredJson);
// 输出: {"name":"孙七","email":"sunqi@example.com"}

✅ 优点:简单直接,适合固定字段筛选。

2. 使用函数自定义过滤逻辑

更灵活的方式是传入一个函数,由你决定每个键值对是否保留:

const user = {
  name: "周八",
  password: "secret",
  token: "xyz789",
  email: "zhouba@example.com",
  age: 32
};

const json = JSON.stringify(user, function (key, value) {
  // 如果是 password 或 token,返回 undefined,表示忽略
  if (key === "password" || key === "token") {
    return undefined;
  }
  // 其他字段原样返回
  return value;
});

console.log(json);
// 输出: {"name":"周八","email":"zhouba@example.com","age":32}

📌 这个技巧在开发 API 接口时特别实用,可以避免敏感信息泄露。


第三个参数:space(格式化输出)

默认情况下,JSON.stringify() 生成的字符串是紧凑的,没有换行和缩进。这在传输时很高效,但不利于人类阅读。

如果你希望输出更美观的格式,可以用第三个参数 space

const data = {
  title: "我的笔记",
  items: [
    { id: 1, content: "学习 JSON" },
    { id: 2, content: "练习 stringify" }
  ],
  author: "开发者小张"
};

// 使用 2 个空格进行缩进
const formattedJson = JSON.stringify(data, null, 2);
console.log(formattedJson);

输出结果如下:

{
  "title": "我的笔记",
  "items": [
    {
      "id": 1,
      "content": "学习 JSON"
    },
    {
      "id": 2,
      "content": "练习 stringify"
    }
  ],
  "author": "开发者小张"
}

📌 space 支持:

  • 数字:表示空格数(如 2、4)
  • 字符串:如 " "(两个空格)、"->"(自定义缩进符)

这个功能在调试阶段非常有用,能让你快速查看数据结构。


特殊值的处理:null、undefined、函数、Symbol

JSON.stringify() 对某些特殊值有明确的处理规则。我们来看几个常见情况:

JavaScript 值 JSON.stringify() 结果 说明
null "null" 会被保留为字符串 "null"
undefined 被忽略(不参与序列化) 不会出现在最终字符串中
function undefined(被忽略) 函数无法序列化
Symbol undefined(被忽略) Symbol 类型不支持 JSON
NaNInfinity null 会被转为 null

实际示例:

const obj = {
  a: null,
  b: undefined,
  c: function () {},
  d: Symbol("id"),
  e: NaN,
  f: Infinity
};

const result = JSON.stringify(obj);
console.log(result);
// 输出: {"a":null,"e":null,"f":null}

📌 从结果可以看到:

  • null 保留了
  • undefinedfunctionSymbol 都被忽略
  • NaNInfinity 被转为 null

⚠️ 重要提醒:如果你的代码中依赖 undefined 作为字段存在,JSON.stringify() 会丢失它!所以要提前做好字段处理。


循环引用问题:如何避免死循环?

在复杂对象中,有时会出现循环引用,比如 A 引用了 B,B 又引用了 A。

const a = { name: "A" };
const b = { name: "B" };

a.ref = b;
b.ref = a; // 循环引用

// 这样会抛出错误!
// JSON.stringify(a); // TypeError: Converting circular structure to JSON

这时 JSON.stringify() 会报错:Converting circular structure to JSON

解决方案:使用 replacer + 弱引用检测

我们可以用 replacer 函数来检测循环引用,避免递归死循环:

const seen = new WeakSet();

const result = JSON.stringify(a, function (key, value) {
  if (typeof value === "object" && value !== null) {
    if (seen.has(value)) {
      return; // 如果已经见过,跳过
    }
    seen.add(value);
  }
  return value;
});

console.log(result);
// 输出: {"name":"A","ref":{"name":"B","ref":{}}}

📌 这个技巧在处理复杂数据模型时非常实用,比如 Vue 3.0 的响应式对象、React 的组件树等。


实际应用:本地存储与 API 通信

1. 本地存储(localStorage)

const userInfo = {
  username: "admin",
  preferences: { theme: "dark", language: "zh-CN" }
};

// 存储前序列化
localStorage.setItem("user", JSON.stringify(userInfo));

// 读取后反序列化
const stored = localStorage.getItem("user");
const parsed = JSON.parse(stored); // 用 JSON.parse 反解
console.log(parsed.username); // "admin"

2. 发送请求到后端

const postData = {
  title: "新文章",
  content: "这是第一篇技术文章。",
  tags: ["JavaScript", "JSON"]
};

fetch("/api/posts", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify(postData) // 必须用 stringify
})
.then(response => response.json())
.then(data => console.log("提交成功", data));

📌 在网络请求中,Content-Type 必须是 application/json,而 body 必须是字符串——这就是 JSON.stringify() 的用武之地。


总结:掌握 JSON.stringify(),就是掌握数据流动的钥匙

JSON.stringify() 看似简单,实则功能强大。它不仅是数据转换的工具,更是前后端协作、本地存储、调试排查的重要环节。

从基础转换到过滤字段,从格式化输出到处理循环引用,每一个细节都值得你深入理解。尤其在现代开发中,无论是 Vue 3.0、React,还是 Node.js 服务端,都离不开它。

记住:

  • 它能处理对象、数组,但不能处理函数、Symbol。
  • 使用 replacer 可以精确控制哪些字段被包含。
  • 使用 space 让输出更易读。
  • 遇到循环引用,用 WeakSet 检测避免崩溃。

掌握这些技巧,你就能在开发中游刃有余地处理各种数据结构问题。下次遇到“数据传不过去”“接口返回空”时,不妨先检查一下是不是少了 JSON.stringify() 这一步。