如何编写函数动态修改嵌套对象指定路径的属性值并返回完整对象?
动态修改嵌套对象指定属性的解决方案
我来帮你搞定这个动态修改嵌套对象的问题~之前用reduce没达到预期效果,大概率是没处理好路径的最后一步或者拷贝逻辑,下面给你两种实用的解决方案,按需选择:
方案一:原地修改原对象(高效直接)
如果不需要保留原对象的初始状态,直接修改原对象是最省事的方式。我们只需要顺着路径找到要修改属性的父节点,然后直接修改对应的值即可:
function updateObject(value, path, obj) { // 找到路径倒数第二个节点(目标属性的父节点) const parentNode = path.slice(0, -1).reduce((current, key) => { return current[key]; }, obj); // 获取路径最后一个键(要修改的属性/索引) const finalKey = path[path.length - 1]; // 修改父节点的对应属性 parentNode[finalKey] = value; // 返回修改后的原对象 return obj; } // 测试用例 let garages = [{ "name": "garage LA", "cars": [{ "car": "Ferrari", "color": "Red" }, { "car": "Rolls Royce", "color": "Purple" }, { "car": "Ferrari", "color": "Orange" } ] }, { "name": "garage SF", "cars": [{ "car": "Mercedes", "color": "Blue" }, { "car": "Ferrari", "color": "Red" } ] }, { "name": "garage NY", "cars": [{ "car": "Aston Martin", "color": "Green" }] }]; // 调用函数 updateObject("Pink", [1, "cars", 1, "color"], garages); console.log(garages[1].cars[1].color); // 输出 "Pink"
方案二:返回新对象(不修改原对象,适合不可变场景)
如果需要保留原对象的初始状态(比如React状态更新场景),我们需要逐层创建新的嵌套结构,避免浅拷贝导致原对象被修改。这里用递归实现不可变更新:
function updateObject(value, path, obj) { // 递归函数:逐层创建新的对象/数组 function traverse(currentPath, currentObj) { // 到达路径终点,返回新值 if (currentPath.length === 0) { return value; } // 拆分当前路径的第一个键和剩余路径 const [currentKey, ...remainingPath] = currentPath; // 创建当前层级的拷贝:数组用slice,对象用展开运算符 const newLayer = Array.isArray(currentObj) ? [...currentObj] : { ...currentObj }; // 递归处理下一层级,替换对应位置的值 newLayer[currentKey] = traverse(remainingPath, currentObj[currentKey]); return newLayer; } return traverse(path, obj); } // 测试用例 let garages = [{ "name": "garage LA", "cars": [{ "car": "Ferrari", "color": "Red" }, { "car": "Rolls Royce", "color": "Purple" }, { "car": "Ferrari", "color": "Orange" } ] }, { "name": "garage SF", "cars": [{ "car": "Mercedes", "color": "Blue" }, { "car": "Ferrari", "color": "Red" } ] }, { "name": "garage NY", "cars": [{ "car": "Aston Martin", "color": "Green" }] }]; // 调用函数,获得新对象 const updatedGarages = updateObject("Pink", [1, "cars", 1, "color"], garages); console.log(updatedGarages[1].cars[1].color); // 输出 "Pink" console.log(garages[1].cars[1].color); // 输出 "Red"(原对象未被修改)
为什么之前用reduce没生效?
如果之前尝试用reduce做不可变更新,很可能是只遍历到了目标节点,却没有逐层创建新的拷贝结构——单纯的reduce只会沿着引用遍历,不会自动生成新的对象/数组,所以看起来像是浅拷贝没产生实际修改效果。上面的方案二里,我们在每一层都创建了当前结构的拷贝,确保原对象的引用不被修改。
扩展提示
你还可以给函数加一些边界判断,比如路径中的键不存在时,自动创建默认的对象或数组(比如如果路径是[3, "cars", 0],而原对象里没有索引3的车库,可以自动创建一个空车库对象),根据你的业务需求调整即可。
内容的提问来源于stack exchange,提问作者Soerman
相关产品推荐
相关产品推荐

