如何从嵌套对象中获取具有值的所有键
Posted
技术标签:
【中文标题】如何从嵌套对象中获取具有值的所有键【英文标题】:How to get all keys with values from nested objects 【发布时间】:2018-04-14 05:55:10 【问题描述】:我正在寻找类似于Object.keys
的东西,但它适用于潜在的嵌套对象。它也不应该包括具有对象/数组值的键(它应该只包括具有直接字符串/数字/布尔值的键)。
示例 A
输入
"check_id":12345,
"check_name":"Name of HTTP check",
"check_type":"HTTP"
预期输出
[
"check_id",
"check_name",
"check_type"
]
Object.keys
适用于这样的扁平案例,但不适用于嵌套案例:
示例 B
输入
"check_id":12345,
"check_name":"Name of HTTP check",
"check_type":"HTTP",
"tags":[
"example_tag"
],
"check_params":
"basic_auth":false,
"params":[
"size"
],
"encryption":
"enabled": true,
预期输出
[
"check_id",
"check_name",
"check_type",
"check_params.basic_auth",
"check_params.encryption.enabled"
]
请注意,这不包括 tags
、check_params
、check_params.params
或 check_params.encryption
,因为这些值是数组/对象。
问题
有没有这样的图书馆?您将如何实现它以便它可以处理任何对象,无论是大的、嵌套的还是小的?
【问题讨论】:
请添加您尝试过的和无效的。 它也不应该包含具有对象/数组值的键 - 但在您的示例 B 中,check_params
被添加到列表中,即使它的值是对象。
@tymeJV Expected output
仅包含 check_params.basic_auth
和 check_params.encryption.enabled
(嵌套键),而不包含具有对象值的 check_params
本身。
【参考方案1】:
你可以像这样使用 reduce:
const keyify = (obj, prefix = '') =>
Object.keys(obj).reduce((res, el) =>
if( Array.isArray(obj[el]) )
return res;
else if( typeof obj[el] === 'object' && obj[el] !== null )
return [...res, ...keyify(obj[el], prefix + el + '.')];
return [...res, prefix + el];
, []);
const input =
"check_id":12345,
"check_name":"Name of HTTP check",
"check_type":"HTTP",
"tags":[
"example_tag"
],
"check_params":
"basic_auth":false,
"params":[
"size"
],
"encryption":
"enabled": true,
"testNull": null,
;
const output = keyify(input);
console.log(output);
Edit1:对于您想要包含数组的一般情况。
const keyify = (obj, prefix = '') =>
Object.keys(obj).reduce((res, el) =>
if( typeof obj[el] === 'object' && obj[el] !== null )
return [...res, ...keyify(obj[el], prefix + el + '.')];
return [...res, prefix + el];
, []);
const input =
"check_id":12345,
"check_name":"Name of HTTP check",
"check_type":"HTTP",
"tags":[
"example_tag"
],
"nested": [
"foo": 0 ,
"bar": 1
],
"check_params":
"basic_auth":false,
"params":[
"size"
],
"encryption":
"enabled": true,
"testNull": null,
;
const output = keyify(input);
console.log(output);
【讨论】:
@NinaScholz 你的意思是如果input
对象是null
?
可能你把enabled
的值从true
改成null
,然后就不行了,因为你少了一张支票。
当我们要返回所有键时,我有一个类似的问题,请添加这个对象 a: 1, b: 2, c: ["a", "b", "c"], z: a: "j", q: "q" 它会返回 ["a", "b", "za", "zq"],我怎样才能显示像 c 这样的所有键?
@YasinFarmani 看看我回答的结尾。 “Edit1:对于您想要包含数组的一般情况。”【参考方案2】:
这是你的意思吗?
http://jsfiddle.net/robbiemilejczak/hfe12brb/1/
我不能用 vanilla JS 做到这一点,这是一个依赖 lodash 的非常 hacky 的解决方案。基本上利用 lodashs _.forIn
和 _.isArray
函数来迭代对象。此外,这只会深入 1 层,因此嵌套对象内的对象将被忽略。不过,它确实会产生您预期的输出,所以我认为这是一个不错的起点。
【讨论】:
【参考方案3】:您可以使用for...in
并创建递归函数。
var obj = "check_id":12345,"check_name":"Name of HTTP check","check_type":"HTTP","tags":["example_tag"],"check_params":"basic_auth":false,"params":["size","a":"b"],"encryption":"enabled":true
var keys = []
function getKeys(data, k = '')
for (var i in data)
var rest = k.length ? '.' + i : i
if (typeof data[i] == 'object')
if (!Array.isArray(data[i]))
getKeys(data[i], k + rest)
else keys.push(k + rest)
getKeys(obj)
console.log(keys)
【讨论】:
具有像全局keys
变量这样明显不必要的副作用可能会向新的 JS 程序员传达错误的信息。只是一个想法。【参考方案4】:
您可以检查键并进行迭代,否则将路径推送到结果集。
function getKeys(object)
function iter(o, p)
if (Array.isArray(o)) return;
if (o && typeof o === 'object')
var keys = Object.keys(o);
if (keys.length)
keys.forEach(function (k) iter(o[k], p.concat(k)); );
return;
result.push(p.join('.'));
var result = [];
iter(object, []);
return result;
var object = check_id: 12345, check_name: "Name of HTTP check", check_type: "HTTP", tags: ["example_tag"], check_params: basic_auth: false, params: ["size"], encryption: enabled: true ;
console.log(getKeys(object));
.as-console-wrapper max-height: 100% !important; top: 0;
【讨论】:
【参考方案5】:生成器可以快速解决此类问题 -
function* deepKeys (t, pre = [])
if (Array.isArray(t))
return
else if (Object(t) === t)
for (const [k, v] of Object.entries(t))
yield* deepKeys(v, [...pre, k])
else
yield pre.join(".")
const input =
check_id:12345,check_name:"Name of HTTP check",check_type:"HTTP",tags:["example_tag"],check_params:basic_auth:false,params:["size"],encryption:enabled:true,testNull:null,
console.log(Array.from(deepKeys(input)))
[ "check_id"
, "check_name"
, "check_type"
, "check_params.basic_auth"
, "check_params.encryption.enabled"
, "check_params.encryption.testNull"
]
或者是一个急切地计算所有键的纯函数表达式 -
const deepKeys = (t, pre = []) =>
Array.isArray(t)
? []
: Object(t) === t
? Object
.entries(t)
.flatMap(([k, v]) => deepKeys(v, [...pre, k]))
: pre.join(".")
const input =
check_id:12345,check_name:"Name of HTTP check",check_type:"HTTP",tags:["example_tag"],check_params:basic_auth:false,params:["size"],encryption:enabled:true,testNull:null,
console.log(deepKeys(input))
[ "check_id"
, "check_name"
, "check_type"
, "check_params.basic_auth"
, "check_params.encryption.enabled"
, "check_params.encryption.testNull"
]
【讨论】:
【参考方案6】:var json =
id: '1234',
test: 'terst',
user :
name: '',
details:
address:
add2:
prim: "",
sec: ""
,
add1: '',
,
salary:
cur: 1234,
net: 89797
,
age: 12
let arr = [];
let initialObj = ;
function getKeys(obj, parentK='')
initialObj = arr.length === 0 ? obj: initialObj;
const entries = Object.entries(obj);
for(let i=0; i<entries.length; i++)
const key = entries[i][0];
const val = entries[i][1];
const isRootElement = initialObj.hasOwnProperty(key);
parentK = isRootElement ? key: parentK+'.'+key;
arr.push(parentK)
if(typeof val === 'object' && val!==null && !Array.isArray(val))
getKeys(val, parentK);
getKeys(json)
console.log('arr final---', arr);
【讨论】:
以上是关于如何从嵌套对象中获取具有值的所有键的主要内容,如果未能解决你的问题,请参考以下文章