已知键名但未知路径时,如何查找并更新对象值?
问题描述
我有数千个嵌套层级差异很大的对象,需要给每个对象里的特定键插入数据。我知道这个键的名称,但不知道它的具体路径。
下面是几个简化示例:
// 示例1 { "fruits": { "apple": { "color": "red" }, "orange": { "color": "orange" } } } // 示例2 { "fruits": { "round": { "apple": { "color": "red" }, "orange": { "color": "orange" } } } } // 示例3 { "apple": { "color": "red" }, "orange": { "color": "orange" } }
我需要一种方法,不用知道具体嵌套路径,就能修改这3个对象里比如"apple"键的值。
说明
- 我已经知道怎么访问该键的值,现在需要修改它的值。
- 该键在每个对象里都是唯一的。
我之前遇到过类似问题,找到了一个查找路径的实现,但它是根据对象值而非键来查找的:
getPath(object: any, value: any) { return Object .keys(object) .reduce((r: any, k: any) => { const kk = Array.isArray(object) ? `[${k}]` : `${k}`; if (object[k] === value) { r.push(kk); } if (object[k] && typeof object[k] === 'object') { r.push(...this.getPath(object[k], value).map((p: any) => kk + (p[0] === '[' ? '' : '.') + p)); } return r; }, []); }
我该怎么解决这个问题?
解决方案
因为目标键是唯一的,我们可以直接通过递归遍历找到目标键并修改值,或者先获取路径再修改,两种方案如下:
方法1:直接遍历修改(高效首选)
直接写一个递归函数遍历对象,找到目标键后立即修改值,无需额外路径处理,性能更优:
modifyObjectByKey(obj: any, targetKey: string, newValue: any): void { // 遍历当前对象的所有键 for (const key of Object.keys(obj)) { // 匹配到目标键,直接修改值 if (key === targetKey) { obj[key] = newValue; return; // 键唯一,找到后直接终止遍历 } // 当前值是对象/数组,递归深入遍历 if (obj[key] && typeof obj[key] === 'object') { modifyObjectByKey(obj[key], targetKey, newValue); } } }
使用示例
// 测试示例1的对象 const obj1 = { "fruits": { "apple": { "color": "red" }, "orange": { "color": "orange" } } }; modifyObjectByKey(obj1, "apple", { "color": "green", "taste": "sweet" }); console.log(obj1.fruits.apple); // 输出: { color: 'green', taste: 'sweet' }
方法2:先获取路径再修改
如果需要先拿到目标键的路径再操作,可以修改原有的getPath函数,改成按键名查找路径:
getPathByKey(obj: any, targetKey: string): string | null { for (const key of Object.keys(obj)) { if (key === targetKey) { return key; } if (obj[key] && typeof obj[key] === 'object') { const nestedPath = getPathByKey(obj[key], targetKey); if (nestedPath) { // 区分数组和对象的路径格式 const prefix = Array.isArray(obj) ? `[${key}]` : `${key}`; return `${prefix}.${nestedPath}`; } } } return null; }
再配合一个通过路径修改值的函数:
setValueByPath(obj: any, path: string, newValue: any): void { const keys = path.split('.'); let current = obj; // 遍历到倒数第二个键,定位到目标键的父级 for (let i = 0; i < keys.length - 1; i++) { const key = keys[i]; // 处理数组索引格式(如"[0]") if (key.startsWith('[') && key.endsWith(']')) { const index = parseInt(key.slice(1, -1), 10); current = current[index]; } else { current = current[key]; } } // 修改目标键的值 const lastKey = keys[keys.length - 1]; if (lastKey.startsWith('[') && lastKey.endsWith(']')) { const index = parseInt(lastKey.slice(1, -1), 10); current[index] = newValue; } else { current[lastKey] = newValue; } }
使用示例
const obj2 = { "fruits": { "round": { "apple": { "color": "red" }, "orange": { "color": "orange" } } } }; const path = getPathByKey(obj2, "apple"); // 输出: "fruits.round.apple" setValueByPath(obj2, path, { "color": "yellow" }); console.log(obj2.fruits.round.apple); // 输出: { color: 'yellow' }
注意事项
- 因为键是唯一的,找到后立即终止遍历能大幅提升处理数千个对象的效率。
- 上述方法会直接修改原对象,如果需要保留原对象,可以在递归前深拷贝,但深拷贝大对象会影响性能,按需选择。
内容的提问来源于stack exchange,提问作者Kurisu
相关产品推荐
相关产品推荐

