2

Currently, I'm trying to get all the keys of an object, including the sub-objects.

I know that

Object.keys(obj)

returns the keys of the object, but not the keys of the objects inside of it.

So, for example, I got following object:

let exampleObject = 
{
   a: "value",
   b: "value",
   c: 404,
   d: {
      e: "value",
      f: "value"
   }
}

NOTE: The d key might change its name, so it won't work to use something like Object.keys(obj.d).

How do I get e and f in my total list of keys existing inside an object?

julianYaman
  • 310
  • 4
  • 13
  • You also want `d` in result or not? – Maheer Ali May 14 '19 at 15:51
  • @MaheerAli Yes, I also want `d` inside. – julianYaman May 14 '19 at 15:52
  • The accepted answer at the link DCR suggested should do it. If you know you only need two levels deep, you can skip the recursion and just add one conditional `Object.keys(prop)` (or something similar) for when `typeof prop == Object`. And if you want to avoid getting the keys of nested arrays, you can further specify `&& !Array.isArray(prop)` (or something similar). – Cat May 14 '19 at 16:00
  • @Cat After looking inside, I also think that it is what I searched for. Thank you for your comment. – julianYaman May 14 '19 at 16:05

2 Answers2

4

You could use flatMap to recursively get the keys like this:

let exampleObject={a:"value",b:"value",c:404,d:{e:"value",f:"value"}};

const getKeys = obj => Object.keys(obj).flatMap(k => Object(obj[k]) === obj[k] 
                                                        ? [k, ...getKeys(obj[k])] 
                                                        : k)

console.log(getKeys(exampleObject))

If flatMap is not supported, use reduce like this:

function getKeys(obj) {
  return Object.keys(obj).reduce((r, k) => {
    r.push(k);

    if(Object(obj[k]) === obj[k])
      r.push(...getKeys(obj[k]));

    return r;
  }, [])
}

The Object(obj[k]) === obj[k] checks if the property is an object and it is not null. Because, typeof null === "object"

adiga
  • 34,372
  • 9
  • 61
  • 83
  • flatMap should make this easy (IF you can count on browser support for it). – Cat May 14 '19 at 16:04
  • 1
    @Cat It would be just a Node.js application running on a server without any frontend so browser support is (in my case) unnecessary. – julianYaman May 14 '19 at 16:08
  • @Cat we should stop worrying about browser support and leave it to the build tools like webpack that can automatically provide exact polyfills for the specified list of browsers our audience is using – marzelin May 14 '19 at 16:14
2

You can try that using recursion.

  • Create a wrapper function getAllKeys() and create an empty array inside that.
  • Now create another function getKeys() which takes object and which will be called recursively.
  • Inside getKeys() loop through the keys using for..in.
  • push() the key into empty array created in wrapper function.
  • Check if the typeof key is "object" then call the function recursively on that.

let exampleObject = 
{
   a: "value",
   b: "value",
   c: 404,
   d: {
      e: "value",
      f: "value"
   }
}

function getAllKeys(obj){
  let res = []
  function getKeys(obj){
    for(let key in obj){
      res.push(key);
      if(typeof obj[key] === "object"){
        getKeys(obj[key])
      }
      
    }
  }
  getKeys(obj);
  return res;
}
console.log(getAllKeys(exampleObject))
Maheer Ali
  • 35,834
  • 5
  • 42
  • 73