JavaScript:自定义extend函数测试不通过原因咨询
首先明确正确的reduce实现核心逻辑:直接修改传入的第一个目标对象,将后续源对象的可枚举自有属性依次赋值上去,最终返回原目标对象本身——核心是复用原目标的引用,而非创建新对象。
你的forEach版本输出符合示例但测试不通过,大概率是以下对象引用或细节处理问题:
1. 返回新对象而非原目标对象
这是最常见的原因。比如你的代码可能先创建了新空对象,把原目标和所有源对象的属性拷贝进去后返回新对象,示例如下:
// 错误写法:返回新对象 function extend(target, ...sources) { let res = {}; // 先拷贝原目标属性 Object.keys(target).forEach(key => res[key] = target[key]); // 再处理源对象 sources.forEach(source => { Object.keys(source).forEach(key => res[key] = source[key]); }); return res; }
这种写法的输出结果和示例一致,但测试用例大概率会检查传入的原目标对象是否被修改,以及返回值是否与原目标对象引用相同。比如测试用例可能包含:
const testTarget = {user: 'barney'}; const result = extend(testTarget, {age:40}); console.log(testTarget === result); // 正确实现应为true,错误写法返回false console.log(testTarget.age); // 正确实现应为40,错误写法中原目标未被修改,返回undefined
这种场景下测试会直接失败。
2. 未严格遍历「可枚举自有属性」
如果你的forEach遍历用了for...in但未加hasOwnProperty判断,或者用了Object.getOwnPropertyNames(会包含不可枚举属性),虽然示例中的属性都是自有可枚举的,输出结果没问题,但测试用例可能包含原型链属性或不可枚举属性的场景,导致结果不符合预期。
错误写法示例:
// 错误:遍历了原型链属性 function extend(target, ...sources) { sources.forEach(source => { for (const key in source) { target[key] = source[key]; } }); return target; }
若某个源对象的原型上存在可枚举属性,这个写法会把原型属性也拷贝过去,而正确的extend应该只处理自有属性。
3. 参数边界处理缺失
比如未处理sources为空、某个源对象是null或undefined的情况。如果你的代码直接对source调用Object.keys(source),当source是undefined时会直接抛出错误,示例运行没问题,但测试用例中的边界场景会失败。
正确的边界处理应该先判断source是否为对象:
// 边界处理示例 sources.forEach(source => { if (source && typeof source === 'object') { Object.keys(source).forEach(key => { target[key] = source[key]; }); } });
总结
最可能的问题是你返回了新对象而非修改并返回原目标对象,导致测试用例检查对象引用时不通过。对比正确的reduce实现就能发现:它以传入的target作为初始值,所有修改都在这个target上进行,最终返回的就是原对象。
内容的提问来源于stack exchange,提问作者utyvert

