
本文介绍一种通用、可复用的递归方法,将任意深度的嵌套对象(含数组)扁平化为键值对结构,支持路径式键名(如 details[0].item_details.number),无需依赖第三方库。
本文介绍一种通用、可复用的递归方法,将任意深度的嵌套对象(含数组)扁平化为键值对结构,支持路径式键名(如 `details[0].item_details.number`),无需依赖第三方库。
在 JavaScript 开发中,常需将嵌套数据结构(如含数组的对象)转换为扁平化的键值映射,尤其在表单序列化、API 参数处理或配置导出等场景中。虽然手动遍历(如 for 循环)能解决特定结构的问题,但缺乏通用性与可维护性。
以下是一个健壮、递归、零依赖的扁平化实现,能正确处理对象、数组及原始值,并自动生成符合预期的点号+方括号路径格式键名:
const flatten = (obj, target = {}, path = '') => {
if (Array.isArray(obj)) {
obj.forEach((item, index) => {
flatten(item, target, `${path}[${index}]`);
});
} else if (obj !== null && typeof obj === 'object') {
Object.keys(obj).forEach(key => {
const newPath = path ? `${path}.${key}` : key;
flatten(obj[key], target, newPath);
});
} else {
target[path] = obj;
}
return target;
};
✅ 使用示例:
const data = {
details: [
{
item_details: {
number: "sdas",
date: "28/07/2022"
}
},
{
item_details: {
number: "hello",
date: "28/07/2022"
}
}
]
};
console.log(flatten(data));
// 输出:
// {
// "details[0].item_details.number": "sdas",
// "details[0].item_details.date": "28/07/2022",
// "details[1].item_details.number": "hello",
// "details[1].item_details.date": "28/07/2022"
// }
? 关键设计说明:
- ✅ 数组识别:使用 Array.isArray() 精准判断,避免 instanceof Array 在跨 iframe 场景下的失效问题;
- ✅ 对象安全检测:obj !== null && typeof obj === 'object' 排除 null,防止原型链误判;
- ✅ 路径拼接逻辑:对根级属性不加前缀(如 details),对嵌套属性自动添加 . 分隔,对数组索引使用 [i] 格式,严格匹配需求输出;
- ✅ 不可变友好:默认创建新对象,不影响原始数据;可通过传入已有 target 实现复用。
⚠️ 注意事项:
- 该函数不处理循环引用,若输入对象存在自引用,将导致栈溢出。生产环境如需支持循环引用,建议引入 WeakMap 缓存已遍历对象;
- 若需兼容 IE,需将箭头函数、const/let 和 Object.keys().forEach() 替换为传统 function 和 for 循环;
- 对于超大规模嵌套(>1000 层),注意浏览器调用栈限制,必要时可改用栈模拟递归。
? 对比结论:
相比硬编码的 for 循环方案,此递归实现具备结构无关性、高复用性与良好可读性,无需引入 Lodash(_.flattenDeep 不适用于对象键路径生成)或其它工具库,是轻量级项目中的推荐实践。如后续需扩展功能(如自定义分隔符、忽略空值、类型过滤),亦可在该基础版本上灵活增强。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











