
本文详解为何递归扁平化对象时 console.log 会执行多次,并提供无副作用、可复用的纯函数式解决方案,确保仅输出一次最终扁平对象。
本文详解为何递归扁平化对象时 `console.log` 会执行多次,并提供无副作用、可复用的纯函数式解决方案,确保仅输出一次最终扁平对象。
在 JavaScript 中对嵌套对象进行递归扁平化时,一个常见误区是将 console.log 放在递归函数内部——这会导致日志随递归深度被多次触发。以您提供的代码为例:
const data = {
id: 9, // 注意:09 是八进制字面量,建议写为 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 newObj = {};
const getFlattenObj = (data) => {
Object.keys(data).forEach(key => {
if (typeof data[key] === 'object' && data[key] !== null) {
getFlattenObj(data[key]); // 递归调用
} else {
newObj[key] = data[key];
}
});
console.log(newObj); // ❌ 错误:每次递归都会执行!
};
getFlattenObj(data);上述代码会输出三次日志,原因在于:
- 第一次调用处理顶层对象(含 id, email, contactInfo),遇到 contactInfo 后递归;
- 第二次调用处理 contactInfo 对象(含 name, address),遇到 address 后再次递归;
- 第三次调用处理 address 对象(含 city, country),无深层嵌套,递归结束。
因此 console.log(newObj) 在每一层递归返回时均被执行,共三次。
✅ 正确做法是:将日志移出递归逻辑,仅在最终结果生成后调用一次;同时避免使用全局变量 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; // ✅ 返回结果,不在此处 log
};
// 使用示例
const flattened = getFlattenObj(data);
console.log(flattened);
// 输出:
// {
// id: 9,
// email: "...",
// name: 'Test1',
// city: 'Berlin',
// country: 'Germany'
// }⚠️ 注意事项:
- 避免全局状态:原方案依赖外部 newObj,多次调用会污染结果;新方案通过参数 target 或默认空对象封装状态,支持连续调用(如 getFlattenObj(obj1); getFlattenObj(obj2);)。
- 类型安全判断:增加 data != null 和 !Array.isArray(value) 检查,防止 null 或数组被误判为可递归对象(数组通常不应扁平为同级键)。
- 数字字面量规范:09 在严格模式下会报错(八进制语法已废弃),应写作 9。
- 如需保留路径前缀(如 contactInfo.name → contactInfo_name),可扩展为带 prefix 参数的版本,但当前需求仅需展平键名,故保持简洁。
总结:递归函数中应严格分离“计算逻辑”与“副作用操作”(如 console.log)。将结果返回、由调用方决定何时/如何输出,是编写健壮、可测试、可复用工具函数的关键原则。

















