如何从JavaScript对象中动态检索任意指定的深度嵌套值?
重新发布为的更正版本。我已经复习过了,但是它没有帮助我处理未知的数组嵌套 编辑:添加了有关Lodash如何从JavaScript对象中动态检索任意指定的深度嵌套值?,javascript,arrays,angular,recursion,nested,Javascript,Arrays,Angular,Recursion,Nested,重新发布为的更正版本。我已经复习过了,但是它没有帮助我处理未知的数组嵌套 编辑:添加了有关Lodash为什么不起作用的信息。这是一个例子。有一个npm库,它可以工作——但是,我不能很好地使用这个包 这适用于Angular应用程序中的列渲染器组件。用户选择要显示的列,并将该列映射到任何列。因此,在下面的示例中,如果用户选择显示“类别”,并将其映射到“兴趣[类别]”,则函数需要在数据中查找对应于该映射的值 样本数据: const response = { id: "1234"
为什么不起作用的信息。这是一个例子。有一个npm库,它可以工作——但是,我不能很好地使用这个包
这适用于Angular应用程序中的列渲染器组件。用户选择要显示的列,并将该列映射到任何列。因此,在下面的示例中,如果用户选择显示“类别”,并将其映射到“兴趣[类别]”,则函数需要在数据中查找对应于该映射的值
样本数据:
const response = {
id: "1234",
version: "0.1",
drinks: ["Scotch"],
interests: [
{
categories: ["baseball", "football"],
refreshments: {
drinks: ["beer", "soft drink"]
}
},
{
categories: ["movies", "books"],
refreshments: {
drinks: ["coffee", "tea", "soft drink"]
}
}
],
goals: [
{
maxCalories: {
drinks: "350",
pizza: "700"
}
}
]
};
对于此数据,可能的映射为:
id
,
版本
,
饮料
,
兴趣[类别]
,
兴趣[点心][饮料]
,
目标[最大热量][饮料]
,
目标[MaxCarries][pizza]
要求:
我需要一个递归函数,该函数将以Angular方式工作,并接受两个参数:一个用于数据对象响应
,另一个用于选择器映射的字符串,该字符串将返回适用的、可能嵌套的值,并遍历遇到的任何对象和/或数组。映射字符串可以有点符号或括号符号。非常需要可读、自文档化的代码
例如,基于上述数据对象:
getValues(“id”,响应)
应返回[“1234”]
getValues(“版本”,响应)
应返回[“0.1”]
getvalue(“饮料”,响应)
应返回[“Scotch”]
getValues(“interests.categories”,response)
应该返回[“棒球”、“足球”、“电影”、“书籍”]
getValues(“兴趣[点心][饮料]”,回复)
应返回[“啤酒”、“软饮料”、“咖啡”、“茶”、“软饮料”]
,以说明兴趣
数组中可能有多少项
getValues(“goals.maxcarries.drinks”,响应)
应返回[“350”]
返回的值最终将被重复数据消除和排序
原始功能:
function getValues(mapping, row) {
let rtnValue = mapping
.replace(/\]/g, "")
.split("[")
.map(item => item.split("."))
.reduce((arr, next) => [...arr, ...next], [])
.reduce((obj, key) => obj && obj[key], row)
.sort();
rtnValue = [...new Set(rtnValue)]; //dedupe the return values
return rtnValue.join(", ");
}
上面的操作很好,就像Lodash'get:如果您通过,例如:“兴趣[0][茶点][饮料]
,它工作得很好。但是,映射不知道嵌套数组,只传入“兴趣[茶点][饮料]“
,这将导致未定义
。必须考虑任何后续数组项
为什么要重新发明轮子?您所描述的正是Lodashget
函数的功能。看
如果你真的想要一个“普通”的解决方案,看看他们是如何做到的。请参见更新
在我给出下面的答案后,我吃了一些晚餐。食物似乎让我意识到我是多么可笑。对于前面的问题,我很清楚我是如何看待这个问题的。但是有一种非常简单的方法,类似于我编写path
函数的方法,只需要少量额外的复杂性来处理数组的映射。这里有一个更干净的方法:
//主函数
const_getValues=([p,…ps])=>(obj)=>
p==未定义
? 数组。isArray(obj)?obj:[obj]
:Array.isArray(obj)
? 对象平面图(o=>_getValues(ps)(o[p]| |[]))
:_getValues(ps)(obj[p]| |[]))
//公共职能
const getValues=(查询,对象)=>
_getValues(query.split(/[\].]+/g.filter(布尔))(obj)
//样本数据
const response={id:“1234”,版本:“0.1”,饮料:[“苏格兰”],兴趣:[{类别:[“棒球”,“足球”],点心:[饮料:[“啤酒”,“软饮料”]},{类别:[“电影”,“书籍”],点心:[饮料:[“咖啡”,“茶”,“软饮料”]}],目标:[{最大卡路里:[饮料:[350],比萨饼:“700”}};
//演示
[
'id',//=>['1234']
'版本',//=>['0.1']
“饮料”、/=>[“苏格兰威士忌”]
“兴趣[类别],//=>[“棒球”、“足球”、“电影”、“书籍”]
“兴趣[点心][饮料],/=>[“啤酒”、“软饮料”、“咖啡”、“茶”、“软饮料”]
'目标.最大卡路里.饮料',/=>['350']
'goals.maxcarries.notFound',//=>
'foo.bar.baz',//=>
“兴趣[类别][饮料],//=>[]
]弗雷奇先生(
name=>console.log(`“${name}”-->${JSON.stringify(getValues(name,response))}`)
)
.as控制台包装{max height:100%!重要;top:0}
使用语法:
const{tokenizePath,resolveValue}=require('path-value');
函数getValues(路径,obj){
const tokens=tokenizePath(path);//以支持完整的ES5语法
返回解析值(obj、令牌);
}
getValues(“id”,响应);//=>1234
看起来你基本上是想实现Lodash的目标。请参阅我在帖子中添加的说明。getValues(“兴趣[点心][饮料]”,回复)代码>无效。索引元素只能是数字或带引号的字符串。您是正确的,但这是从数据库返回并传递给函数的字符串。因此,在原始问题中,replace.split.map.reduce
方法的舞蹈将输入字符串转换为更可接受的内容:[“兴趣”、“点心”、“饮料”]
在下面的答案中,这在一行中处理得更加优雅:query.split(/[\].]+/g).filter(布尔)
仍然需要将对象扫描迁移到typescript,以便angular可以处理它。。。一旦我到了itLodash get,我可能会在这里发布一些信息,比如:\uuu.get(响应,“兴趣[0].categories”,“默认”)代码>但是,将要传递的是:兴趣.类别
(不带ar