Converting Nested Objects to Flat Objects in JavaScript: A Quick Guide

I am sure you have been asked this question in one of the interviews.


It looks simple at first. But the interviewer is actually checking whether you understand recursion, objects, and how JavaScript treats arrays.


So, basically, you are given a nested object, and you are expected to simplify it by removing the nesting and printing it in a non-nested format.

Here is a simple input and output:

const input = {
  a: 1,
  b: {
    c: 2,
    d: {
      e: 3
    }
  }
};

Output:

 {  a: 1, 
    b_c: 2, 
    b_d_e: 3, 
 }

Now, look at the solution:

function flatten(obj, prefix = "", res = {}) {
    // Loop through every key in the object
    for (let key in obj) {

        // Skip properties coming from prototype chain
        if (!obj.hasOwnProperty(key)) return;

        // If prefix exists, append current key using _
        // Otherwise just use the key itself
        let objKey = prefix ? `({prefix}_){key}` : key;

        let value = obj[key];

        // If value is an object and not null,
        // recursively flatten it
        if (typeof value === 'object' && value !== null) {
            flatten(value, objKey, res);
        } else {
            // If it's a primitive value, assign it directly
            res[objKey] = value;
        }
    }

    // Return the accumulated result
    return res;
}


Let us test it.

const input = {
  a: 1,
  b: {
    c: 2,
    d: {
      e: [1, 2]
    }
  }
};

console.log(flatten(input));

//  {a: 1, b_c: 2, b_d_e_0: 1, b_d_e_1: 2 }


Now, observe something interesting.


It flattens the nested object correctly.


But it also destructures the array and adds indexes as keys.


Why do you think that happened?

💡

As you know, everything in JavaScript is an object. Even Arrays.


So, when we check:

typeof value === 'object'


Arrays also satisfy that condition.


That means our recursive call is going inside arrays as well, and treating indexes (0, 1) like object keys.


That is why we are getting:

b_d_e_0: 1
b_d_e_1: 2

So, how do we fix it?

Simple.


We add one more condition to ignore Arrays.

function flatten(obj, prefix = "", res = {}) {
    for (let key in obj) {

        // Ensure we are working only with object's own properties
        if (!obj.hasOwnProperty(key)) return;

        let objKey = prefix ? `({prefix}_){key}` : key;
        let value = obj[key];

        // Only recurse if:
        // 1. value is an object
        // 2. value is not null
        // 3. value is NOT an array
        if (
            typeof value === 'object' &&
            value !== null &&
            !Array.isArray(value)
        ) {
            flatten(value, objKey, res);
        } else {
            // Directly assign primitives and arrays
            res[objKey] = value;
        }
    }

    return res;
}

Testing Both Cases

const input1 = {
  a: 1,
  b: {
    c: 2,
    d: {
      e: [1, 2]
    }
  }
};

const input2 = {
  a: 1,
  b: {
    c: 2,
    d: {
      e: 3
    }
  }
};

console.log(flatten(input1));
console.log(flatten(input2));

// { a: 1, b_c: 2, b_d_e: [ 1, 2 ] }
// { a: 1, b_c: 2, b_d_e: 3 }

That is it.


A simple recursion problem. But it tests whether you truly understand:

  • How objects work
  • How arrays behave internally
  • How recursion accumulates results
  • And how small edge cases can break your logic


This is why interviewers love this question.


That’s all, folks! I hope you found this helpful. If you enjoyed this, check out more articles on my Blog, https://blog.nandan.dev/


Feel free to comment, email me at connect@nandan.dev, or connect with me on Twitter, Instagram, or GitHub. Don’t forget to subscribe to my newsletter for regular updates on JavaScript topics!


Twitter | Instagram | Github | Website

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.