如何用扩展运算符结合柯里化函数更新深拷贝对象的指定属性
问题解决
1. 柯里化修改函数修正
你现有代码的问题是遍历datasets时没有判断第二个下标inx,导致当前分组下所有dataset的label都被修改,修正后的函数如下:
const changeDatasetLabel = (index) => (idx) => (value) => { dataSet = dataSet.map((group, groupIndex) => { // 不是目标分组直接返回原对象,复用引用 if (groupIndex !== index) return group // 是目标分组,拷贝外层,修改datasets字段 return { ...group, datasets: group.datasets.map((item, itemIndex) => { // 不是目标子项直接返回原对象 if (itemIndex !== idx) return item // 是目标子项,拷贝对象,修改label属性 return { ...item, label: value } }) } }) }
调用changeDatasetLabel(0)(1)("新值")就只会修改dataSet[0].datasets[1].label,和直接赋值效果一致,且不会修改原对象的其他引用。
额外提示:如果是在React项目中使用,建议把dataSet声明为useState状态,修改时直接调用set方法即可触发组件重渲染,示例:
const [dataSet, setDataSet] = useState(/* 初始数组 */) const changeDatasetLabel = (index) => (idx) => (value) => { setDataSet(prev => prev.map((group, groupIndex) => { if (groupIndex !== index) return group return { ...group, datasets: group.datasets.map((item, itemIndex) => { if (itemIndex !== idx) return item return { ...item, label: value } }) } })) }
2. 深拷贝通俗易懂讲解
核心概念区分
- 浅拷贝:只复制对象/数组的第一层结构,深层嵌套的对象/数组还是和原对象共享同一块内存地址,修改深层属性时原对象也会跟着变。我们常用的扩展运算符
...、Object.assign、数组的slice/concat都属于浅拷贝。 - 深拷贝:完整复制对象所有层级的结构,拷贝后的对象和原对象完全独立,没有任何共享的引用,修改任意一方都不会影响另一方。
常用实现方式
- 简单场景可以用
JSON.parse(JSON.stringify(待拷贝对象)),缺点是无法处理函数、Symbol、undefined、循环引用等特殊值。 - 复杂场景可以手写递归实现拷贝,或者直接用成熟的工具函数实现全量深拷贝。
你当前场景的最佳实践
你现在用的map+扩展运算符的方式属于不可变更新,不需要做全量深拷贝:只修改需要变化的节点,其他未变化的节点直接复用原有引用,性能比全量深拷贝高很多,同时也满足React状态更新的依赖对比要求。
内容的提问来源于stack exchange,提问作者Somi
相关产品推荐
相关产品推荐

