返回与深度嵌套的Javascript对象中搜索到的键相对应的值



我在Javascript中有一个如下的对象,

const obj = {
"group1": {
"sub_group1_1": {
"inner_sub_group1_1_1": {
"name": "abc"
},
"inner_sub_group1_1_2": {
"name": "def"
}
},
"sub_group1_2": {
"inner_sub_group1_2_1": {
"name": "ghi"
},
"inner_sub_group1_2_2": {
"name": "jkl" 
}
}
},
"group2": {
"sub_group2_1": {
"inner_sub_group2_1_1": {
"name": "mno"
},
"inner_sub_group2_1_2": {
"name": "pqr"
}
},
"sub_group2_2": {
"inner_sub_group2_2_1": {
"name": "stu"
},
"inner_sub_group2_2_2": {
"name": "wxy" 
}
}
}
}

我想写一个函数,它可以在上面的对象中搜索一个密钥,并向我返回该密钥的相应值,例如

输入

filterObject(obj, 'inner_sub_group2_2_2')

输出

{
"name": "wxy
}

输入

filterObject(obj, 'inner_sub_group1_1_1')

输出

{
"name": "abc
}

方法

我已经为它编写了一个递归函数,但它似乎不适用于第二种情况,

const filterObject = (obj, searchedKey) => {
let result = {};
for (const key in obj) {
const currentObj = obj[key];
if (key === searchedKey) {
result = currentObj;
break;
} else if (typeof currentObj === 'object') {
result = filterObject(currentObj, searchedKey);
}
}
return result;
};

任何形式的帮助都将不胜感激。谢谢

您需要能够检查递归调用是否找到了什么,而您没有这样做——现在,您只是重新分配result,然后忽略它,继续循环的下一次迭代。

一种适用于这种特殊情况的方法是检查结果对象是否有任何键。

const obj={group1:{sub_group1_1:{inner_sub_group1_1_1:{name:"abc"},inner_sub_group1_1_2:{name:"def"}},sub_group1_2:{inner_sub_group1_2_1:{name:"ghi"},inner_sub_group1_2_2:{name:"jkl"}}},group2:{sub_group2_1:{inner_sub_group2_1_1:{name:"mno"},inner_sub_group2_1_2:{name:"pqr"}},sub_group2_2:{inner_sub_group2_2_1:{name:"stu"},inner_sub_group2_2_2:{name:"wxy"}}}};
const filterObject = (obj, searchedKey) => {
if (searchedKey in obj) {
return obj[searchedKey];
}
for (const key in obj) {
const currentObj = obj[key];
if (typeof currentObj === 'object') {
const result = filterObject(currentObj, searchedKey);
if (Object.keys(result).length) return result;
}
}
return {};
};
console.log(filterObject(obj, 'inner_sub_group2_2_2'));
console.log(filterObject(obj, 'inner_sub_group1_1_1'));

但是,如果找到的值不是对象,或者找到的对象为空,则这将不起作用。(将返回与原始结构未连接的不同对象引用。)

对于更一般的情况,递归调用应该返回两件事:是否找到嵌套值,以及找到的值(如果有的话)。一种方法是,如果找到了某个对象,则返回该对象,而不返回其他对象。

const obj={group1:{sub_group1_1:{inner_sub_group1_1_1:{name:"abc"},inner_sub_group1_1_2:{name:"def"}},sub_group1_2:{inner_sub_group1_2_1:{name:"ghi"},inner_sub_group1_2_2:{name:"jkl"}}},group2:{sub_group2_1:{inner_sub_group2_1_1:{name:"mno"},inner_sub_group2_1_2:{name:"pqr"}},sub_group2_2:{inner_sub_group2_2_1:{name:"stu"},inner_sub_group2_2_2:{name:"wxy"}}}};
const filterObject = (obj, searchedKey) => {
if (searchedKey in obj) {
return { result: obj[searchedKey] };
}
for (const key in obj) {
const currentObj = obj[key];
if (typeof currentObj === 'object') {
const result = filterObject(currentObj, searchedKey);
if (result) return result;
}
}
};
console.log(filterObject(obj, 'inner_sub_group2_2_2').result);
console.log(filterObject(obj, 'inner_sub_group1_1_1').result);

代码中的问题是,如果递归调用成功,循环仍在继续,同时进行另一个可能不成功的递归调用,因此丢失了良好的result

在那个递归调用之后,您需要一个if,它检测成功并在成功的情况下爆发。

现在,为了区分失败和成功,如果在没有成功的情况下返回null,事情会变得更容易。

需要调整两条线路:

const filterObject = (obj, searchedKey) => {
let result = null; // To indicate nothing found yet
for (const key in obj) {
const currentObj = obj[key];
if (key === searchedKey) {
result = currentObj;
break;
} else if (typeof currentObj === 'object') {
result = filterObject(currentObj, searchedKey);
if (result) break; // <--- break out when success!
}
}
return result;
};

您的is对象测试可能需要一些改进,因为typeof null === 'object'是一个真实的表达式。

你可以用这个代替:

if (Object(currentObj) === currentObj)

以下是@trincot和@secuneperformance答案的变体。没有什么新的东西,只是略有不同的风格:

const obj={group1:{sub_group1_1:{inner_sub_group1_1_1:{name:"abc"},inner_sub_group1_1_2:{name:"def"}},sub_group1_2:{inner_sub_group1_2_1:{name:"ghi"},inner_sub_group1_2_2:{name:"jkl",spoiler:null}}},group2:{sub_group2_1:{inner_sub_group2_1_1:{name:"mno"},inner_sub_group2_1_2:{name:"pqr",xtr:false}},sub_group2_2:{inner_sub_group2_2_1:{name:"stu"},inner_sub_group2_2_2:{name:"wxy"}}}};
function deepGet(obj,k,r){ // call with two arguments only
if(obj&&typeof obj=="object") {
if(k in obj) return obj[k];
for(l in obj) if((r=deepGet(obj[l],k))!=null) return r;
}
return null;
}
console.log(['inner_sub_group2_2_2','inner_sub_group1_1_1','xtr'].map(k=>deepGet(obj,k)));

最新更新