问题
I'm looking for something kind of like Object.keys
but that works for potentially nested objects. It also shouldn't include keys that have object/array values (it should only include keys with immediate string/number/boolean values).
Example A
Input
{
"check_id":12345,
"check_name":"Name of HTTP check",
"check_type":"HTTP"
}
Expected output
[
"check_id",
"check_name",
"check_type"
]
Object.keys
would work for flat cases like this, but not for nested cases:
Example B
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,
}
}
}
Expected output
[
"check_id",
"check_name",
"check_type",
"check_params.basic_auth",
"check_params.encryption.enabled"
]
Note that this does not include tags
, check_params
, check_params.params
, or check_params.encryption
since these values are arrays/objects.
The question
Is there a library that does this? How would you implement it so that it can work with any object, large and nested, or small?
回答1:
You could use reduce like this:
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 + '.')];
} else {
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);
回答2:
You could check the keys and iterate otherwise push the path to the result set.
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; }
回答3:
You can use for...in
and create recursive function.
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)
回答4:
Here's one way you can do it
const isPlainObject = x =>
Object (x) === x && ! Array.isArray (x)
const formatKey = (...segments) =>
segments .join ('.')
const deepKeys = (o, pre = [], acc = []) =>
Object
.keys (o)
.reduce
( (acc, k) =>
isPlainObject (o [k])
? [ ...acc, ...deepKeys (o [k], [ ...pre, k ], acc) ]
: [ ...acc, formatKey (...pre, k) ]
, []
)
const data =
{ a: 1
, b: 2
, c: { d: 3
, e: [ 4, 'a', 'b', 'c' ]
, f: { g: 5
, h: 6
}
}
}
console .log (deepKeys (data))
// [ 'a'
// , 'b'
// , 'c.d'
// , 'c.e'
// , 'c.f.g'
// , 'c.f.h'
// ]
回答5:
Is this what you mean?
http://jsfiddle.net/robbiemilejczak/hfe12brb/1/
I couldn't do it with vanilla JS, and this is a pretty hacky solution that relies on lodash. Basically leverages lodashs _.forIn
and _.isArray
functions to iterate over an object. Also this will only go 1 layer deep, so objects inside of nested objects will be ignored. It does produce your expected output though, so I'd say it's a decent starting point.
来源:https://stackoverflow.com/questions/47062922/how-to-get-all-keys-with-values-from-nested-objects