我正在尝试找到一种方法来动态创建一个数组,该数组包含嵌套对象中最深层属性的路径。例如,如果我的对象如下:
{
userName: [],
email: [],
name: {
fullName: [],
split: {
first: [],
last: []
}
},
date: {
input: {
split: {
month: [],
year: []
},
full: []
},
select: {
month: [],
year: []
}
}
};
我需要一个数组来包含类似的内容:
["userName", "email", "name.fullName", "name.split.first",...]
是否有任何内置或外部库可以自动执行此操作?我试图在父对象上使用 Object.keys 但这只返回直接子属性。
最佳答案
您可以使用Array.prototype.flatMap
为此-
const d =
{userName:[],email:[],name:{fullName:[],split:{first:[],last:[]}},date:{input:{split:{month:[],year:[]},full:[]},select:{month:[],year:[]}}}
const main = (o = {}, path = []) =>
Array.isArray(o) || Object(o) !== o
? [ path ]
: Object
.entries(o)
.flatMap(([ k, v ]) => main(v, [...path, k ]))
console.log(main(d))
输出
[ [ "userName" ]
, [ "email" ]
, [ "name", "fullName" ]
, [ "name" ,"split", "first" ]
, [ "name", "split", "last" ]
, ...
]
<小时/>
如果您希望路径为 "a.b.c"
而不是[ "a", "b", "c" ]
,使用.map
和Array.prototype.join
-
const d =
{userName:[],email:[],name:{fullName:[],split:{first:[],last:[]}},date:{input:{split:{month:[],year:[]},full:[]},select:{month:[],year:[]}}}
const main = (o = {}, path = []) =>
Array.isArray(o) || Object(o) !== o
? [ path ]
: Object
.entries(o)
.flatMap(([ k, v ]) => main(v, [...path, k ]))
console.log(main(d).map(path => path.join(".")))
输出
[
"userName",
"email",
"name.fullName",
"name.split.first",
"name.split.last",
"date.input.split.month",
"date.input.split.year",
"date.input.full",
"date.select.month",
"date.select.year"
]
<小时/>
如果您不想依赖Array.prototype.flatMap
由于您的环境不支持它,因此您可以使用 Array.prototype.reduce
的组合和Array.prototype.concat
-
const d =
{userName:[],email:[],name:{fullName:[],split:{first:[],last:[]}},date:{input:{split:{month:[],year:[]},full:[]},select:{month:[],year:[]}}}
const main = (o = {}, path = []) =>
Array.isArray(o) || Object(o) !== o
? [ path ]
: Object
.entries(o)
.reduce // <-- manual flatMap
( (r, [ k, v ]) =>
r.concat(main(v, [...path, k ]))
, []
)
console.log(main(d).map(path => path.join(".")))
或者你可以填充 Array.prototype.flatMap
-
Array.prototype.flatMap = function (f, context)
{ return this.reduce
( (r, x, i, a) => r.concat(f.call(context, r, x, i, a))
, []
)
}
<小时/>
Is there a way to access any of those properties' value? Eg.
"d.name.split.first"
using the returned array at position 3?
我们可以编写一个接受对象的查找函数,o
,以及点分隔的字符串 s
,如果可能的话返回一个值,否则返回 undefined
如果s
无法访问 -
const d =
{userName:[],email:[],name:{fullName:[],split:{first:[],last:[]}},date:{input:{split:{month:[],year:[]},full:[]},select:{month:[],year:[]}}}
const lookup = (o = {}, s = "") =>
s
.split(".")
.reduce
( (r, x) =>
r == null ? undefined : r[x]
, o
)
console.log(lookup(d, "name.split"))
// { first: [], last: [] }
console.log(lookup(d, "name.split.first"))
// []
console.log(lookup(d, "name.split.zzz"))
// undefined
console.log(lookup(d, "zzz"))
// undefined
关于javascript - 检索对象中最深层属性的路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57778629/