
本文详解为何递归扁平化对象时 console.log 被触发多次,并提供无副作用、可复用的纯函数式解决方案,确保仅输出一个最终扁平对象。
本文详解为何递归扁平化对象时 `console.log` 被触发多次,并提供无副作用、可复用的纯函数式解决方案,确保仅输出一个最终扁平对象。
在 JavaScript 中对嵌套对象进行扁平化处理时,若将 console.log 直接置于递归函数内部(如 getFlattenObj),会导致日志被多次打印——这并非数据错误,而是递归调用逻辑的自然结果。
以原始代码为例:
const newObj = {};
const getFlattenObj = (data) => {
Object.keys(data).forEach(key => {
if (typeof data[key] === 'object') {
getFlattenObj(data[key]); // 递归调用 → 新一层执行上下文
} else {
newObj[key] = data[key];
}
});
console.log(newObj); // ✅ 每次递归返回前都执行一次!
};当传入含两层嵌套的对象(contactInfo → address),该函数共被调用 3 次:
- 第 1 次:处理顶层 data(触发 contactInfo 分支);
- 第 2 次:处理 contactInfo 对象(触发 address 分支);
- 第 3 次:处理 address 对象(无子对象,直接落到底层 else 分支后 log)。
因此 console.log(newObj) 被执行三次,且每次输出的是同一全局对象 newObj 的当前状态(逐步累积),造成冗余与混淆。
✅ 正确做法是:
- 移除递归函数内的副作用操作(如 console.log);
- 避免依赖外部可变状态(如全局 newObj),改用参数传递或局部创建目标对象;
- 统一在递归调用完成后,由最外层调用者决定何时输出或返回结果。
优化后的推荐实现如下(纯函数、无副作用、支持多次调用):
const getFlattenObj = (data, target = {}) => {
if (data == null || typeof data !== 'object') return target;
Object.keys(data).forEach(key => {
const value = data[key];
if (value != null && typeof value === 'object' && !Array.isArray(value)) {
getFlattenObj(value, target); // 递归写入同一 target
} else {
target[key] = value;
}
});
return target;
};
// ✅ 安全使用示例
const data = {
id: 9,
email: '<a class="__cf_email__" data-cfemail="82e3e0e1c2f6e7f1f6ace1edef" href="/cdn-cgi/l/email-protection">[email protected]</a>',
contactInfo: {
name: 'Test1',
address: {
city: 'Berlin',
country: 'Germany'
}
}
};
const flattened = getFlattenObj(data);
console.log(flattened);
// 输出:{ id: 9, email: '...', name: 'Test1', city: 'Berlin', country: 'Germany' }? 关键改进点说明:
- 使用默认参数 target = {} 替代全局变量,保障函数纯净性与可重入性;
- 增加 null 和 Array.isArray 校验,防止数组被误展开(扁平化通常只处理 plain object);
- 所有递归调用共享同一 target 引用,避免对象拷贝开销;
- return target 使函数具备明确返回值,调用方完全控制后续操作(如日志、校验、链式处理)。
⚠️ 注意事项:
- 该方案为「浅合并式扁平化」,同名键会被深层值覆盖(如 contactInfo.name → name);
- 若需保留路径前缀(如 contactInfo_name),应扩展逻辑传入 prefix 参数;
- 不适用于循环引用对象,生产环境建议配合 WeakMap 做循环检测。
通过重构递归逻辑与作用域设计,即可彻底解决多日志问题,并获得健壮、可维护的对象扁平化工具函数。

















