DEV Community

Cover image for How to Traverse an Object of Arbitrary Depth in JavaScript
Nick Scialli (he/him)
Nick Scialli (he/him)

Posted on • Originally published at typeofnan.dev

How to Traverse an Object of Arbitrary Depth in JavaScript

Sometimes we find that we need to traverse an object and perform some operation on it at some arbitrary depth. While this seems like a tough challenge, we can make use of recursion, mutability, and object references to get the job done in short order.


If you enjoy this tutorial, please give it a ๐Ÿ’“, ๐Ÿฆ„, or ๐Ÿ”– and consider:

๐Ÿ“ฌ signing up for my free weekly dev newsletter
๐ŸŽฅ subscribing to my free YouTube dev channel


Our Example Challenge: Deep Word Replacement

Let's say we have an object that all the text fields of a dog adoption application our user has provided us. However, the user entered [tbd] in the places where the dog's name should beโ€”picking a dog's name is hard. Alas, our user has finally selected the name Daffodil for his puppy, and we must now replace all the [tbd] strings in our object.

Unfortunately, our object is complex and of arbitrary depth. We must make this string replacement anywhere in our object!

Here's our object:

const application = {
  section1: {
    question1: {
      text: "What will your pet's name be?",
      response: '[tbd]',
    },
    question2: {
      text: 'What will the names of all the pets in your house be?',
      response: ['Fred', 'Whiskers', '[tbd]'],
      subquestion2: {
        text: 'How will you take care of your new pet?',
        response: 'I will feed [tbd] three times a day and pat her head.',
      },
    },
  },
};
Enter fullscreen mode Exit fullscreen mode

Let's think about this problem in steps before we write our solution. Here's what we need to do:

  • Create a function that takes an object as an argument.
  • For each key in that object, if that key is a string, do our word replace. (mutation!)
  • If the key is an object, send that key back through the initial function (recursion!)

We can see how this looks in JavaScript:

function replaceTbd(obj) {
  for (let key in obj) {
    if (typeof obj[key] === 'string') {
      obj[key] = obj[key].replace('[tbd]', 'Daffodil');
    }
    if (typeof obj[key] === 'object') {
      replaceTbd(obj[key]);
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Kind of simple actually! Let's see if that works on our object.

replaceTbd(application);

console.log(application);
/*
{
  section1: {
    question1: {
      text: "What will your pet's name be?",
      response: 'Daffodil',
    },
    question2: {
      text: 'What will the names of all the pets in your house be?',
      response: ['Fred', 'Whiskers', 'Daffodil'],
      subquestion2: {
        text: 'How will you take care of your new pet?',
        response: 'I will feed Daffodil three times a day and pat her head.',
      },
    },
  },
};
*/
Enter fullscreen mode Exit fullscreen mode

Success! Do note that we didn't return anthing from our replaceTbd functionโ€”it's mutating our input object as it dives down the tree! If this isn't desired behavior, you could consider looking into a deep clone library to first clone your object and then mutate the clone.

Conclusion

Working with deep objects can be intimidating, but it gets much easier when you master the concepts of recursion, mutability, and object references.


If you enjoy this tutorial, please give it a ๐Ÿ’“, ๐Ÿฆ„, or ๐Ÿ”– and consider:

๐Ÿ“ฌ signing up for my free weekly dev newsletter
๐ŸŽฅ subscribing to my free YouTube dev channel

Top comments (3)

Collapse
 
256hz profile image
Abe Dolinger • Edited

A quick and dirty way is to stringify your object and perform a regex replace:

const newApplication = JSON.parse(JSON.stringify(application).replace('[tbd]', 'Daffodil'))

It's likely this is more performant as well, but I haven't tested it. It also introduces the possibility of some nasty bugs if your new input isn't sanitized in some way, so your method is certainly better in that regard.

Collapse
 
nas5w profile image
Nick Scialli (he/him)

But this fails quite readily if any part of your object isn't stringifiable as JSON!

Collapse
 
256hz profile image
Abe Dolinger

Also true! Just works for your example