JavaScript对象遍历方法与JSON数据转换代码案例

作者:拾光

时间:2026-10-30

浏览:229

深入解析JavaScript中对象的多种遍历方法及JSON字符串与对象之间的转换技巧,包含完整代码示例、常见陷阱分析与结构图解。

文章目录

在前端业务与服务端接口交互过程中,JavaScript 对象的属性遍历以及与 JSON 字符串互相转换是最基础也是最高频的操作。本文系统梳理各种遍历手段的差异、JSON 双向转换的具体规则,并通过完整的代码案例与图解帮助开发者正确选型与避坑。

一、JavaScript 对象遍历的核心机制与方法对比

JavaScript 提供了多种遍历普通对象属性的方式。开发者常因未能区分“自身属性与原型链属性”以及“枚举属性与不可枚举属性”而引发偶发 Bug。理解各种遍历手段的边界是写出健壮代码的前提。

JavaScript对象遍历方法与JSON数据转换代码案例
图 1:JavaScript 对象遍历常用 API 核心特征对比

1. for...in 循环及原型链属性防护

for...in 语句以任意顺序遍历一个对象自有的及原型链上继承的可枚举属性(Symbol 属性除外)。正因为其会沿着原型链向上查找,容易意外遍历出原型中添加的自定义函数或属性。

// 示例对象与原型继承定义
const protoObj = { inheritedRole: "guest" };
const userProfile = Object.create(protoObj);
userProfile.name = "Alice";
userProfile.age = 26;

// 使用 for...in 遍历并过滤自身属性
for (const key in userProfile) {
  // 推荐使用 ES2022 引入的 Object.hasOwn 进行属性归属判断
  if (Object.hasOwn(userProfile, key)) {
    console.log(`[自有属性] ${key}: ${userProfile[key]}`);
  } else {
    console.log(`[原型属性] ${key}: ${userProfile[key]}`);
  }
}
// 示例输出:
// [自有属性] name: Alice
// [自有属性] age: 26
// [原型属性] inheritedRole: guest

2. Object.keys()、Object.values() 与 Object.entries()

在现代 ECMAScript 开发中,推荐优先使用 Object.keys()、Object.values() 和 Object.entries()。这组方法只返回对象自身(非继承)的可枚举字符串属性数组,能够无缝结合 forEach()、map() 或 for...of 进行遍历。

const product = {
  id: "P-1001",
  name: "机械键盘",
  price: 299,
  stock: 45
};

// 1. 获取所有键
const keys = Object.keys(product);
console.log("所有键:", keys); // 示例输出: ['id', 'name', 'price', 'stock']

// 2. 获取所有值
const values = Object.values(product);
console.log("所有值:", values); // 示例输出: ['P-1001', '机械键盘', 299, 45]

// 3. 遍历键值对 (结合解构赋值)
for (const [key, val] of Object.entries(product)) {
  console.log(`字段名: ${key.padEnd(6, ' ')} -> 当前值: ${val}`);
}
// 示例输出:
// 字段名: id     -> 当前值: P-1001
// 字段名: name   -> 当前值: 机械键盘
// 字段名: price  -> 当前值: 299
// 字段名: stock  -> 当前值: 45

3. 处理 Symbol 属性与不可枚举属性

如果对象的键中使用了 Symbol 或者通过 Object.defineProperty 定义了 enumerable: false,前述方法均会静默忽略。此时需使用 Object.getOwnPropertySymbols() 或全量反射接口 Reflect.ownKeys()。

const privateKey = Symbol("token");
const account = {
  username: "developer_01",
  [privateKey]: "secret_hash_9876"
};

// 定义一个不可枚举属性
Object.defineProperty(account, "internalId", {
  value: "SYS-999",
  enumerable: false
});

// Reflect.ownKeys 可一次性读取所有自身键 (包括字符串、Symbol、不可枚举)
const allKeys = Reflect.ownKeys(account);
console.log("全量键:", allKeys);
// 示例输出: ['username', 'internalId', Symbol(token)]

二、JSON 数据转换标准流程与底层机制

JSON(JavaScript Object Notation)是一种纯文本数据交换格式。JavaScript 内置的全局 JSON 对象提供了 JSON.stringify()(对象序列化为 JSON 文本)和 JSON.parse()(JSON 文本解析为对象)两个核心 API。二者不仅支持直接转换,还提供了用于深度定制处理的 replacer 和 reviver 回调参数。

JavaScript对象遍历方法与JSON数据转换代码案例
图 2:JavaScript 对象与 JSON 字符串双向序列化流水线

1. JSON.stringify() 语法与高级用法

JSON.stringify(value, replacer, space) 支持接收三个参数:

  • value: 将要转为 JSON 字符串的值。
  • replacer (可选): 转换函数或键名白名单数组。若是函数,对象的每个属性都会调用它,返回的值决定最终输出。
  • space (可选): 用于美化输出的空格数或占位字符(最多 10 个空格)。
const orderData = {
  orderId: "ORD-20261024",
  customer: "Zhang San",
  status: "PAID",
  paymentTime: new Date("2026-10-24T14:00:00Z"),
  internalAuthToken: "hidden_token_888", // 敏感字段需过滤
  customTags: ["VIP", "Rush"]
};

// 案例 1:使用白名单数组过滤指定属性
const briefJson = JSON.stringify(orderData, ["orderId", "status", "customer"]);
console.log("白名单过滤结果:", briefJson);
// 示例输出: {"orderId":"ORD-20261024","status":"PAID","customer":"Zhang San"}

// 案例 2:使用 replacer 函数处理特定字段并格式化缩进
const formattedJson = JSON.stringify(orderData, (key, value) => {
  if (key === "internalAuthToken") {
    return undefined; // 返回 undefined 会使该属性在序列化中被剔除
  }
  return value;
}, 2);
console.log("格式化输出:\n" + formattedJson);

2. JSON.parse() 与日期字段自动还原

JSON 规范中并没有“日期”类型,Date 对象在经过 JSON.stringify 处理后会被转换为 ISO 格式的字符串。当使用 JSON.parse 读回时,默认仍是普通字符串。通过传入 reviver 函数,可以在解析阶段将特定格式的字符串自动重建为真实 Date 实例。

const rawJsonString = '{"reportTitle":"月度总结","publishedAt":"2026-10-24T06:00:00.000Z","readCount":1240}';

// 定义 ISO 8601 时间戳正则
const isoDateFormat = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;

const parsedReport = JSON.parse(rawJsonString, (key, value) => {
  if (typeof value === "string" && isoDateFormat.test(value)) {
    return new Date(value); // 还原为真实 Date 对象
  }
  return value;
});

console.log("还原后字段类型:", Object.prototype.toString.call(parsedReport.publishedAt));
// 示例输出: [object Date]
console.log("可直接调用日期方法:", parsedReport.publishedAt.getFullYear());
// 示例输出: 2026

三、实战案例:复杂 JSON 对象的遍历清洗与数据重构

在实际业务中,接口返回的数据往往包含多层嵌套、空字符串、null 占位或者冗余字段。我们需要将对象遍历技术与 JSON 转换结合起来,完成数据过滤、深度转换和落盘准备。

JavaScript对象遍历方法与JSON数据转换代码案例
图 3:嵌套数据对象清洗并重新打包为 JSON 的标准操作步骤

下面是一个可直接执行的完整案例:编写一个 cleanAndSerialize 函数,它能深层遍历任意复杂的嵌套对象,递归剔除所有值为 null、undefined 或空字符串的属性,并将驼峰命名(camelCase)字段统一转换为下划线(snake_case)命名输出为 JSON。

// 驼峰转下划线辅助函数
function camelToSnake(str) {
  return str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
}

// 递归遍历并清洗对象
function cleanAndTransformObject(target) {
  // 基本类型及 null 直接返回
  if (target === null || typeof target !== "object") {
    return target;
  }

  // 数组处理:保持索引顺序,递归清洗子项
  if (Array.isArray(target)) {
    return target
      .map(item => cleanAndTransformObject(item))
      .filter(item => item !== null && item !== undefined && item !== "");
  }

  // 普通对象:使用 Object.entries() 遍历键值对并重构
  const cleanedResult = {};
  for (const [key, value] of Object.entries(target)) {
    // 过滤无效空值
    if (value === null || value === undefined || value === "") {
      continue;
    }

    const newKey = camelToSnake(key);
    cleanedResult[newKey] = cleanAndTransformObject(value);
  }

  return cleanedResult;
}

// 测试数据
const rawApiResponse = {
  userName: "Bob",
  userAge: 30,
  emptyField: "",
  nullableScore: null,
  contactDetails: {
    phoneNumber: "13800000000",
    backupEmail: null,
    homeAddress: "北京市海淀区"
  },
  skillTags: ["JavaScript", "", "Node.js"]
};

// 执行清洗与转换
const cleanedData = cleanAndTransformObject(rawApiResponse);
const finalJsonString = JSON.stringify(cleanedData, null, 2);

console.log("最终清洗转换后的 JSON 字符串:\n" + finalJsonString);
// 示例输出:
// {
//   "user_name": "Bob",
//   "user_age": 30,
//   "contact_details": {
//     "phone_number": "13800000000",
//     "home_address": "北京市海淀区"
//   },
//   "skill_tags": [
//     "JavaScript",
//     "Node.js"
//   ]
// }

四、常见陷阱与技术选型总结

在日常处理对象遍历与 JSON 转换时,有几个关键边界需要重点防范:

  • 循环引用崩溃:当一个对象的某个属性直接或间接指向自身时,执行 JSON.stringify 会抛出 TypeError: Converting circular structure to JSON。解决办法是使用 WeakSet 记录已访问对象,或者在序列化前解除环形引用。
  • 特殊数据类型的丢失:
    • undefined、函数以及 Symbol 作为对象属性值时,在 JSON.stringify 中会被直接忽略;若出现在数组中,则会被转为 null。
    • NaN 和 Infinity 会被转为 null。
    • RegExp、Map、Set、Error 会被转为空对象 {}。
  • 深拷贝的误用:开发者常使用 JSON.parse(JSON.stringify(obj)) 实现快速深拷贝,但该方式仅适用于包含纯字面量类型、布尔值、数字、字符串和普通数组的对象。若包含日期、函数或正则表达式,会导致原型链和类型丢失。现代浏览器推荐优先使用原生 structuredClone(obj)。
JavaScript对象遍历方法与JSON数据转换代码案例
图 4:JavaScript 对象遍历与 JSON 转换核心实践总结
核心总结: 遍历对象时,优先选用 Object.keys() 与 Object.entries(),可规避原型链继承干扰;在进行 JSON 序列化和解析时,合理利用 replacer 和 reviver 函数能有效完成敏感信息脱敏和特殊对象类型(如 Date)的无损还原。面对深拷贝需求,应优先采用标准 API structuredClone(),避免简易 JSON 序列化带来的类型丢失。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章