I'm trying to get all the keys in an object, in a recursive way:
let keys = [];
const getAllKeys = (object) => {
//Supposedly, `keys` should be here.
Object.keys(object).some((k) => {
if (object[k] && typeof object[k] === "object") {
keys.push(k);
getAllKeys(object[k]);
}
});
return keys;
};
const obj = {
key1: {
key2: {
key3: {}
}
}
};
getAllKeys(obj);
console.log(keys);
And as you can see, it works, but the problem is that keys is outside this function, but I need it to be inside so that I can just import this function and use it. I tried wrapping it in another, inner function, but it doesn't work.
What can I do here?
You need a wrapper function to hold the accumulator:
const getAllKeys = (object) => {
let keys = [];
let getAllKeysInner = (o) => {
Object.keys(o).forEach((k) => {
keys.push(k);
if (o[k] && typeof o[k] === "object") {
getAllKeysInner(o[k]);
}
});
}
getAllKeysInner(object)
return keys;
};
//
const obj = {
key1: {
key2: {
key3: {}
}
}
};
console.log(getAllKeys(obj))
Note that your code needed a few fixes.
FWIW, this particular problem can be done simpler, without any accumulator at all:
const getAllKeys = (o) =>
(o && typeof o === "object")
? Object.keys(o).flatMap(k => [k, ...getAllKeys(o[k])])
: []
although the accumulator version might be more efficient since it doesn't allocate 1000s temporary arrays.
Finally, the VLAZ's idea to carry the accumulator around is a sane one, because is it as efficient as the wrapper version. It can be written concisely like this:
const getAllKeys = (o, keys=[]) =>
o
&& typeof o === "object"
&& Object.keys(o).forEach(k => keys.push(k) && getAllKeys(o[k], keys))
|| keys
You can convert keys to a parameter you pass recursively:
const getAllKeys = (object, keys = []) => {
Object.keys(object).some((k) => {
if (object[k] && typeof object[k] === "object") {
keys.push(k);
getAllKeys(object[k], keys);
}
});
return keys;
};
const obj = {
key1: {
key2: {
key3: {}
}
}
};
const result = getAllKeys(obj);
console.log(result);
This does mean that the first call might be getAllKeys(obj, ["some" "keys", "already", "present"]) or even something invalid like getAllKeys(obj, null). If you want to make sure that doesn't happen, convert your function to a recursion helper function and you can have a top level function that makes sure to call it correctly:
const getAllKeys = (object) => {
const helper = (object, keys) => {
// ^^^^^^ now an internal helper
Object.keys(object).some((k) => {
if (object[k] && typeof object[k] === "object") {
keys.push(k);
helper(object[k], keys);
// ^^^^^^ recursively calls itself
}
});
return keys;
}
//top level function just calls the helper:
return helper(object, []);
};
const obj = {
key1: {
key2: {
key3: {}
}
}
};
const result = getAllKeys(obj);
console.log(result);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With