NEW!

Joystick: The Full-Stack JavaScript Framework Learn More

# How to Recursively Traverse an Object with JavaScript

## What You Will Learn in This Tutorial

How to write a function that looks for a specific key/value pair on an object and call that function recursively to traverse objects of an arbitrary depth.

## Getting Started

For this tutorial, we're going to create a simple, single file Node.js project. On your computer, choose a good location for your file (e.g., a projects folder) and create a file called `index.js`.

Next, make sure that you've installed Node.js on your computer. While the code we write will not depend on Node.js to work, we'll need it to run or execute the code we write inside of `index.js`.

Once you have your file created and Node.js installed, we're ready to get started.

## Creating a function to match objects by key and value

An easy way to understand the concept of recursion is to think of a spiral staircase in a house. In order to go from the top of the staircase to the bottom, you need to walk down one step at a time.

Though you do it automatically, technically you have a "function" in your brain that tells you how to walk down one step at a time until you reach the bottom. You call that "function" for each step in the staircase until there are no more steps. As you walk down, you tell the "function" to call itself again if there's a step after the current one.

This is how recursion works in JavaScript (or any programming language). You write a function that performs a task and have that function call itself again if it hasn't met some requirement—for example, finding a nested value or reaching the end of a list.

For this tutorial, we're going to write a function that focuses on the former: finding a nested object. More specifically, we want to write a recursive function that finds a nested object containing a specific key with a specific value.

First, let's create our base function and explain what it's up to:

/index.js

``````const findNestedObject = (object = {}, keyToMatch = "", valueToMatch = "") => {
// We'll implement our function here...
};
``````

Our function will take three arguments: an `object` to traverse, a `keyToMatch` within that object, and a `valueToMatch` within that object.

/index.js

``````const isObject = (value) => {
return !!(value && typeof value === "object" && !Array.isArray(value));
};

const findNestedObject = (object = {}, keyToMatch = "", valueToMatch = "") => {
if (isObject(object)) {
// We'll work on finding our nested object here...
}

return null;
};
``````

Next, in order to avoid any runtime errors, in the body of our `findNestedObject` function, we add an `if` statement with a call to a new function we've added above `isObject()`, passing in the `object` argument that was passed to `findNestedObject`.

Looking at `isObject()`, we want to be certain that the object we're traversing is actually an object. To find out, we need to verify that the passed `value` is not null or undefined, has a `typeof` "object," and it is not an array. That last one may look odd. We need to do `!Array.isArray()` because in JavaScript, `Array`s have a `typeof` "object" (meaning that our previous `typeof value === "object"` test can be "fooled" by an array being passed).

Assuming that `isObject()` returns `true` for the value we passed it, we can start to traverse the object. If not, as a fallback, from our `findNestedObject()` function we return `null` to signify that we did not find a match.

/index.js

``````const isObject = (value) => {
return !!(value && typeof value === "object" && !Array.isArray(value));
};

const findNestedObject = (object = {}, keyToMatch = "", valueToMatch = "") => {
if (isObject(object)) {
const entries = Object.entries(object);

for (let i = 0; i < entries.length; i += 1) {
const [treeKey, treeValue] = entries[i];

if (treeKey === keyToMatch && treeValue === valueToMatch) {
return object;
}
}
}

return null;
};
``````

Adding some complexity, now, we want to begin the traversal of our object. By "traverse" we mean looping over each key/value pair on the `object` passed in to `findNestedObject()`.

To do that loop, we first call to `Object.entries()` passing in our `object`. This will return us an array of arrays, where each array contains the `key` of the key/value pair currently being looped over as the first element and the `value` of the key/value pair currently being looped over as the second element. Like this:

``````const example = {
first: 'thing',
second: 'stuff',
third: 'value',
};

Object.entries(example);

[
['first', 'thing'],
['second', 'stuff'],
['third', 'value']
]
``````

Next, with our array of key/value pairs (entries), we add a `for` loop to iterate over the array. Here, `i` will equal the index of the current key/value pair we're looping over. We want to do that until we've looped over all entires so we say "run this loop while `i < entries.length` and for each iteration, and `1` to the current index `i`."

Inside of the `for` loop, we use JavaScript array destructuring to access the current key/value pair array (denoted by `entries[i]`), assigning each a variable. Here, we assign the first element to the variable `objectKey` and the second element to the variable `objectValue`.

Remember: our goal is to find an object by the passed `keyToMatch` and `valueToMatch`. In order to find a match, we need to check each key and value on our `object` to see if they're a match. Here, assuming that we find a match, we return the `object` as it fulfilled the requirement of having the `keyToMatch` and `valueToMatch`.

## Adding recursion to traverse objects of an arbitrary depth

Now for the fun part. Right now, our function can only loop over a single-level depth object. This is great, but remember, we want to search for a nested object. Because we don't know where that object might be in the "tree" (a nickname you will occasionally hear for an object of nested objects), we need to be able to "keep going" if one of the values in the key/value pairs is itself an object.

This is where our recursion comes in.

/index.js

``````const isObject = (value) => {
return !!(value && typeof value === "object" && !Array.isArray(value));
};

const findNestedObject = (object = {}, keyToMatch = "", valueToMatch = "") => {
if (isObject(object)) {
const entries = Object.entries(object);

for (let i = 0; i < entries.length; i += 1) {
const [objectKey, objectValue] = entries[i];

if (objectKey === keyToMatch && objectValue === valueToMatch) {
return object;
}

if (isObject(objectValue)) {
const child = findNestedObject(objectValue, keyToMatch, valueToMatch);

if (child !== null) {
return child;
}
}
}
}

return null;
};
``````

Remember our staircase analogy from earlier. At this point, we've only walked down one step. In order to step down to the next step, we need to tell our function to call itself again.

In this case, we know there is another "step" or object to traverse if passing `objectValue` to the `isObject()` function we set up earlier returns `true`. If it does, that means that we need to check if that object contains the `keyToMatch` and `valueToMatch` we're looking for.

To traverse that object, we recursively (meaning, to call the function we're currently inside of again), passing in the `objectValue` along with the original `keyToMatch` and `keyToValue` (what we're looking for hasn't changed, just the object we want to look at).

If our recursive call finds a match (meaning our recursive call to `findNestedObject()` does not return `null`), we return that object `child`. Assuming that our recursive call to `findNestedObject()` did not return a match, our traversal would stop. If our child itself had nested objects (keeping with our analogy, another "step" to walk down), again, we'd call `findNestedObject()`.

Because this code is recursive, it will run until it either finds a matching object, or, exhausts the available nested objects to search.

Now for a test. Let's try to find the object in this tree with a `name` field equal to "Down here!"

/index.js

``````const isObject = (value) => {
return !!(value && typeof value === "object" && !Array.isArray(value));
};

const findNestedObject = (object = {}, keyToMatch = "", valueToMatch = "") => {
if (isObject(object)) {
const entries = Object.entries(object);

for (let i = 0; i < entries.length; i += 1) {
const [objectKey, objectValue] = entries[i];

if (objectKey === keyToMatch && objectValue === valueToMatch) {
return object;
}

if (isObject(objectValue)) {
const child = findNestedObject(objectValue, keyToMatch, valueToMatch);

if (child !== null) {
return child;
}
}
}
}

return null;
};

const staircase = {
step: 5,
nextStep: {
step: 4,
nextStep: {
step: 3,
nextStep: {
step: 2,
nextStep: {
name: "Down here!",
step: 1,
},
},
},
},
};

const match = findNestedObject(staircase, "name", "Down here!");
console.log(match);
// { name: "Down here!", step: 1 }

const match2 = findNestedObject(staircase, "step", 3);
console.log(match2);
// { step: 3, nextStep: { step: 2, nextStep: { name: "Down here!", step: 1 } } }
``````

Here's a quick demo of this running in real-time:

## Wrapping up

In this tutorial, we learned how to recursively traverse an object using JavaScript. We learned how to create a base function that was able to loop over the keys of an object we passed it, looking for a matching key and value pair. Then, we learned how to use that function recursively, calling it from within itself if the value of the key/value pair we were currently looping over was an object.

#### Get the latest free JavaScript and Node.js tutorials, course announcements, and updates from CheatCode in your inbox.

No spam. Just new tutorials, course announcements, and updates from CheatCode.

#### Cart

Your cart is empty!

• Subtotal

\$0.00

• Total

\$0.00