Home

WTF is deep-for-each?

Explore an introduction to the super cool, single-function JavaScript package, deep-for-each.

deep-for-each is a JavaScript package that ships a single function used for recursively iterating over an object. It is most useful when wanting to manipulate or extract from an object with an unpredictable structure.

How deep-for-each Works

If we were to import the deep-for-each function as deepForEach, the usage would look like this:

import deepForEach from "deep-for-each";

deepForEach(movie, (value, key, subject, path) => {
// do something ...
});

The function accepts two arguments — the object and the callback. The callback is fired for every property within the object, providing access to the following for that property:

  • value: The property's value, which may include descendants if the property is an object or array of objects.
  • key: The property's key.
  • subject: The surrounding object — i.e. the property's parent and parents' descendants.
  • keyPath: The path to the property from the original object.

Let's walk through a couple quick examples ...

Example #1: Callback Arguments

Say we have a movie object that contains a bunch of data for a given film. I just watched a silly movie, Jumanji: The Next Level, so let's use that as our example. Here's a snippet of that film might look like:

const movie = {
name: "Jumanji: The Next Level",
year: "2019",
cast: [
{
actor: {
name: "Dwayne Johnson",
},
character: {
name: "Bravestone",
},
},
{
actor: {
name: "Karen Gillan",
},
character: {
name: "Ruby",
},
},
],
};

If I were to run the deep-for-each function over that object, displaying the output in each available callback, the code to execute it would be something like this:

import deepForEach from "deep-for-each";

deepForEach(movie, (value, key, subject, path) => {
console.log("KEY:", key);
console.log("VALUE:", value);
console.log("SUBJ:", subject);
console.log("PATH:", path);
});

For the first key-value pair — the top-level name — that would log the following:

KEY: name
VALUE: Jumanji: The Next Level 
SUBJ: { name: 'Jumanji: The Next Level', 
  year: '2019', 
  cast:  
   [ { actor: [Object], character: [Object] }, 
     { actor: [Object], character: [Object] } ] } 
PATH: name

But, then let's say we're in the first cast member's real name. That would look like this:

KEY: name
VALUE: Dwayne Johnson 
SUBJ: { name: 'Dwayne Johnson' } 
PATH: cast[0].actor.name 

Example #2: Creating New Properties

Now, suppose I couldn't predict the structure of this object, but I wanted to provide a title alias to every name property. I could look for name keys and set a title if one doesn't already exist. It'd look like this:

deepForEach(movie, (value, key, subject, path) => {
if (key === "name" && !subject.title) subject.title = value;
});

That says if we run into a name property where there is not a sibling title property, then we duplicate the name property as title. If we were to check the value of movie after running this recursive function, we'd see this:

{
"name": "Jumanji: The Next Level",
"year": "2019",
"cast": [
{
"actor": {
"name": "Dwayne Johnson",
"title": "Dwayne Johnson"
},
"character": {
"name": "Bravestone",
"title": "Bravestone"
}
},
{
"actor": {
"name": "Karen Gillan",
"title": "Karen Gillan"
},
"character": {
"name": "Ruby",
"title": "Ruby"
}
}
],
"title": "Jumanji: The Next Level"
}

While that may not be super practical, it demonstrates how flexible and powerful this function can be.

Warning: Be Careful!

As always, with great power comes great responsibility. So, while this is really powerful and can clean up some gnarly code, it also means you have to be careful. It's going to be much easier to screw something up along the way.

Let's Connect

Keep Reading

WTF is React?

A brief introduction to React, along with a list of references for more learning.

Jun 29, 2020

WTF is Node.js?

An brief introduction to Node.js, along with links to dig in further with a tutorial or course.

Jun 29, 2020

WTF is NPM?

A brief description of NPM.

Jun 29, 2020