We all know it. Javascript is great.
Until it isn’t.
It’s super easy to use.
Until it isn’t.
And there’s a way to do just about anything you want in JS. From DOM manipulation to client server architecture. From machine learning to IoT. Truly javascript has an answer for everything, right?
As condescending of an intro as that was, I do genuinely feel that Javascript (or Typescript) is the future. That being said, the language and its frameworks aren’t without their problems. I would like to submit to you as a for instance my favorite programming meme, featuring Patrick Star and Manta Ray.
Plugging this into a console, we find that what is shown holds true. But I’m not here to talk bad about JS. My goal with this post is to propose that (some of) the problems we face with programming languages aren’t in fact problems with the language itself, but how we as programmers are approaching the task at hand.
Enter: Recursion.
Being a Rubyist at heart, learning Javascript had its curve. Somethings I liked better in Ruby, somethings made more sense in Javascript. One example of this was the JS for
loop, and more specifically the for…of
loop.
When I discovered the for…of
loop, it was like the world had been hidden from me. “Surely this is the pinnacle of human innovation” I thought. Being able to iterate over an array with such little syntax was a miracle.
And of course JS, like almost all other common languages has a while
loop, which does something as long as a given expression is true (or crashes your computer if you’re not careful).
So if a common for loop iterates over a collection of data x
amount of times (or for as many times as is equal to the length of the collection) and the while loop goes on and on as long as something remains true… can I tell Javascript to do something UNTIL something is true?
This was a question that bothered me more and more as I continued to learn JS. I could in theory manipulate one of the aforementioned iterators to act in such a manner, but the function almost always ended up being more intricate than I felt was necessary. Then one day during a code session, I was doing some googling unrelated to the problem statement and I saw recursion being used, and it all clicked.
I’m sure that many of you reading this are familiar with the concept of recursion, but I’m going to define it anyway for my own peace of mind.
Recursion is defined as a repeated application of recursive procedures. (Long form for ‘something is being repeated’.)
“Yeah okay, that’s awesome, but how does that help me?”
Let’s look at a sandbox example.
This measly six lines of code will return a factorial of any number given to the function. This function is a common sandbox problem, with many different ways to solve it, however with recursion implemented, the function can be as short as possible. Let’s break it down.
As an example, say we plugged in 8
to the function. In the first line, the function checks to see if the n
is less than or equal to 1
. Since it is not, we continue, and return the value of whatever the product of n
times n-1
is. Because of recursion, we can call this function ONCE with the desired number as n
, and it will loop through, decreasing by 1
UNTIL n
is equal to or less than 1
. Thats a lot to take in, especially if you’re not familiar with recursion. Here is this function in action:
(For reference, a factorial is the product of a number times every number less than it, greater than 0.)
This function takes the number 8, multiplies it by 7, multiplies THAT product by 6, then THAT product by 5… etc. all the way down to 1, all in 6 lines of code. This would be irresponsibly complicated without recursion.
Recursion along with an if
statement solves my, albeit unnecessary, desire for Javascript to have an until loop.
But honestly, that example was a bit too esoteric to really get a grasp on how awesome recursion really is. Let’s see a practical use.
reactJack
Recently, I built a black jack simulator. In the game of black jack, each player including the dealer is initially dealt two playing cards.
In the dealFirstTwo()
function, the variable index
will create a random number between 0
and (initially) 51
. It will find a card
inside of an array of objects I created called wholeDeck
containing all 52
playing cards whose index in the array corresponds to the index
variable. It will then set the dealt
property of that found card
object to true. The sortDeck()
function sets the variable sortedDeck
equal to all the objects inside the wholeDeck
array whose dealt
property equals false
, which on the first pass is every card except the first card
‘dealt’. Then, the function will push the found card
into the hand
that is passed in as a parameter to the function (either playerHand
or dealerHand
, both just empty arrays initially). Finally, the function checks the length of the hand
passed in as a parameter, and if the length is not equal to or greater than 2
, it will repeat the function.
TL;DR: Give me a random number, find a card inside of a deck based on that number, tell that card its been dealt, tell the deck that card has been dealt, tell the player that the card belongs to it, and if the player doesn’t have two cards in his hand, give it another card.
Calling this function twice, with playerHand
and dealerHand
passed into the function as parameters respectively, we can efficiently deal two cards to a player and a dealer (and in theory, and as many players as needed).
And for one last example, another function in my blackjack simulator that handles the initial players turn uses recursion as well.
This function is a bit longer, but accomplishes the same idea. UNTIL a player either busts or chooses to stay, keep giving the player a card.
Here we have an if…else
statement, with another if…else
statement nested inside the else branch of the initial.
Line by line we have this:
If playerTotal
(a variable set as the total of all values of the cards in a given hand) is greater than 21
, tell the player ‘you’ve busted’, show the hidden dealer card, and then seeWhoWon()
. If playerTotal
is not greater than 21
, send a confirmation window telling the player their total
, and asking the player if they want another card (this returns a boolean value). If the player wants to hit, the dealOne()
function deals one card (this function is the same as the function dealFirstTwo()
above, without the recursive if
statement). The playerTotal
will be updated, showTertiaryPlayerCards()
will show the card dealt on the screen, and after 500 milliseconds, the function will repeat. If the player does not want to hit, we pass the turn to the dealer, which is a similar function with a few more specifications for my very (very) simple ‘A.I.’.
TL;DR: Check to see if player has busted. If not, ask if they want a card. If they do, give them one, and repeat. If they don’t, its the dealers turn. If they busted, the dealer doesn’t get a turn, because the dealer wins automatically.
Hopefully this has cleared up the idea of recursion for some, and if not maybe it was able to show you the utility behind the idea.
Cheers!
Top comments (2)
For "until", wouldn't
while (!expression)
work? Or did I miss something?i had not considered using bang in a while loop when i wrote this. i will play around with it later today to see