So recursion can save us code,
it can also solve problems which we couldn't solve with a for loop
Let's say we have a constant, myself and I'm an object with a name, Max and with some friends and friends
could be an array right because it's a list of friends.
Now every friend also is an object, an object with a name,
for example Manuel and maybe also some friends,
so here a nested array. Here we could have some fictional friend, Chris
and there we got no friends because Chris doesn't have friends,
whatever.
Now i also have another friend and that could be Julia
and let's say she also has no friends but what we do have here therefore is a bunch of objects which
all have the same structure, a name and potentially some friends and they can be nested as deep as you
want,
Chris could have friends,
Julia could have friends.
So we don't know how many levels of nesting we have here
and that's not just a fictional problem, you could encounter this in many applications you're writing.
Let's say you're building an application like Dropbox where you want to render a folder structure, well
every folder could have subfolders,
so then you would have exactly this data structure behind the scenes.
You don't know how many folders the user of your application is going to create but you will have the
same kind of object just nested at different levels,
you don't know how many levels of nesting you'll need.
So therefore, we could have a scenario like this where we know we have the same kind of objects nested
into each other in the end but we don't know how many.
Now if we wanted a function, print friend names, then we can't use a for loop here to loop through all
the friends because here of course, I could expect to get a person as an input and I could then try to
go through all friends of person.friends but now as you learned, for Max for example, I have Manuel
who also has friends, so I would need a nested for loop here, friends, friends of
friends.friends,
so this is now for nested friends but for one, not every person has friends,
that's a problem
so I maybe tried to loop through friends which aren't there, like in the case of Julia
and even if a person has friends like Manuel does, then I don't know if I need another nested loop
because here, the friends of Manuel, in this case Chris also might have friends
and even if I would know how many levels of nesting I have which I don't, we would have tons of nested
for loops which is pretty hard to read code.
So in the best case, we know how many loops we need, then it's hard to read, in the worst case which will
often be the case, you don't know how many levels of nesting you need because that data might not be hard
coded by you but you might be downloading that from some database,
maybe it then was created by users of your application, so at the point of time you're writing your code,
you can't know how many levels of nesting you'll have,
so this then even isn't an option,
this is where recursion can really shine.
Here we could create a collected names constant or variable,
now we can add a for loop in here,
we need one where we go through all friends of person.friends,
so if I passed in my self here, I would access the friends property and now go through this array
and add the friends to the collected names, to be precise friends.name and then here, we could return
the collected names.
Now we don't use recursion yet,
let's still see what we get here
If I console log the result of print friend names for myself which is that constant here. If we do that
and we save that and we reload, I see Manuel and Julia because these are the direct friends of myself.
Now we want to use recursion to go through all nested friends friends as well. For this inside of the
for loop, instead of just pushing the friend names here, we can call print friend names again and we pass
in friend because print friend names expects a person, so it expects an object with a friends key and
when we go through my friends here, we get such objects.
Now maybe they don't all have friends though, this friends key might not exist for every nested object.
So inside of print friend names, we should add an if check and check if person.friends is a thing
and if it's falsy, hence the exclamation mark at the beginning, so if we don't have a truthy value for
the friends key, so if it's undefined effectively like it is for Julia or for Chris, then we just return
here, to be precise
we return an empty array because then this person has no friends,
otherwise we make it to the for loop where we go through all friends of friends.
Now i expect print friend names or maybe we should call it get friend name therefore to return a
list of friends.
So here actually, what gets returned here is always an array,
either an empty one or one of the names. For that we should still push every friend.name to our collected
names
and then in the end, return collected names which also is an array, so that get friend names always returns
an array.
Now what do we do with that return value of get friend names inside of get friend names which is our
recursive call? Well in the end, that will be all the names of the friend we're looking at here in this
for/of loop and we want to add these names to the collected names array we're merging here. So here
we can simply say collectedNames.push and now however we have to be careful because that will return
an array and I don't want to add that array as a nested array to our array here,
instead we can use the spread operator to spread this into multiple individual pieces and since push
takes multiple arguments, as many as we want, these will then be added one by one to our collected names
array
and with that if we also update the name down there to avoid errors, if we save that and reload, we get
a list where Manuel, Chris and Julia are included and these are my friends here,
Manuel,
Chris and Julia
and if Chris also had some friends where we again have a name, Harry, and maybe another friend where we
also have a name, Amelia,
then these two names will also be included if we reload,
here they are, because we now have recursion to go through that data structure here. And you see how
flexible this approach is,
we can easily add more friends and deeper and deeper nesting of friends and due to the way how this
function is written and the logic we have in there,
this will go through as many levels of nesting as we need because it doesn't care, it calls itself and
dives into the friends until there are no more friends for a given person and then it returns and returns
and returns until it's done with the outermost function call where then it returns the overall value.
Now recursion can be difficult to wrap your head around but the developer tools can help you just as i showed
you, add some breakpoints and carefully step through the execution to get a feeling for where you are
at and how it works and then the idea is that you have a function which calls itself and then uses the
return value of that internal function call.
You always need some exit condition,
otherwise you'll get an infinite call stack and this will break your app and throw an error
but as long as you have that and you're sure that it can be met, you have a powerful tool to save
code as we did here or to go through data structures which you couldn't really go through otherwise.