不可变更新嵌套数组遇引用相等问题求助
问题原因与解决方案
问题根源
你的update函数直接将原对象dest作为reduce的初始累加器acc,这意味着整个函数没有创建新的顶层对象,而是直接修改了原对象的属性,最终返回的updated其实就是原obj的引用。所以updated.a和obj.a自然指向同一个数组(即使你创建了新数组赋值给acc[key],但acc本身就是原对象,相当于直接修改了原对象的a属性,updated和obj是同一个引用)。
修复方案
要实现不可变更新,核心是从原对象的副本开始修改,而不是直接操作原对象。只需要修改reduce的初始值为原对象的浅拷贝即可:
function update(dest, source) { // 用原对象的浅拷贝作为累加器初始值,避免修改原对象 return Object.entries(source).reduce((acc, [key, val]) => { if (Array.isArray(val)) { acc[key] = [...val]; } else if (isPlainObject(val)) { // 递归更新嵌套对象,update已返回新对象,无需额外展开 acc[key] = update(dest[key], source[key]); } else { acc[key] = val; } return acc; }, {...dest}); // 关键修改:创建原对象的副本 } function isPlainObject(obj) { return Object.prototype.toString.call(obj) === '[object Object]'; } const obj = { a: [1, 2], }; const updated = update(obj, { a: [1, 2] }); console.log(updated.a === obj.a); // 输出 false
额外说明
- 修改后,
updated是一个全新的顶层对象,其a属性是新创建的数组,因此updated.a !== obj.a符合预期。 - 对于嵌套对象,递归调用
update时同样会创建对应层级的副本,保证整个嵌套结构的不可变性。
内容的提问来源于stack exchange,提问作者Andy Jessop
相关产品推荐
相关产品推荐

