
本文详解为何递归扁平化对象时控制台会多次打印结果,并提供无副作用、可复用的纯函数式解决方案,确保仅输出一个最终扁平对象。
本文详解为何递归扁平化对象时控制台会多次打印结果,并提供无副作用、可复用的纯函数式解决方案,确保仅输出一个最终扁平对象。
在 JavaScript 中对嵌套对象进行扁平化处理时,若将 console.log 直接置于递归函数内部,极易引发意外的多次输出——这正是原代码的核心问题。原始实现中,getFlattenObj 每次递归调用(进入 contactInfo、再进入 address)都会独立执行一次 console.log(newObj),导致共三次日志,而非预期的“仅一次最终结果”。
根本原因在于:日志语句与递归逻辑耦合,且依赖全局变量 newObj。每次递归层级返回前都打印当前状态,而 newObj 是跨调用共享的,造成日志冗余与状态污染。
✅ 正确做法是:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 将日志移出递归函数体,仅在顶层调用后输出;
- 避免全局状态,改用参数传递或函数内创建目标对象;
- 返回扁平化结果,使函数具备纯函数特性(无副作用、可复用、易测试)。
以下是优化后的推荐实现:
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 getFlattenObj = (data, targetObject = {}) => {
Object.keys(data).forEach(key => {
const value = data[key];
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
getFlattenObj(value, targetObject);
} else {
targetObject[key] = value;
}
});
return targetObject;
};
const newObj = getFlattenObj(data);
console.log(newObj);
// 输出:{ id: 9, email: '...', name: 'Test1', city: 'Berlin', country: 'Germany' }
? 关键改进说明:
- ✅ 日志解耦:console.log 仅在最终调用处执行,确保单次输出;
- ✅ 消除全局变量:targetObject 作为默认参数传入,每次调用互不影响,支持多轮独立使用;
- ✅ 健壮性增强:增加 value !== null && !Array.isArray(value) 判断,避免数组被误展开(数组通常不参与扁平化,除非业务明确需要);
- ✅ 数值安全:修正 id: 09 → id: 9,防止八进制解析歧义(ES5+ 中带前导零的整数字面量已弃用)。
? 小结:递归函数的设计应遵循“输入→处理→输出”原则,避免在中间层级产生副作用(如日志、DOM 操作、全局状态修改)。将副作用移至调用边界,不仅能精准控制执行时机,也大幅提升代码可维护性与可预测性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










