DEV Community

Cover image for Recursive FizzBuzz in JavaScript
oksanadev
oksanadev

Posted on

Recursive FizzBuzz in JavaScript

The Fizz Buzz test is a simple example of a tech interview question designed to test job candidates. It reads as follows:

Write a function that prints the numbers from 1 to 100. For multiples of three print “Fizz” instead of the number and for multiples of five print “Buzz” instead of the number. For numbers which are multiples of both three and five print “FizzBuzz”.

It is a basic exercise to practice conditionals and modulo/remainder operator. If you can think of one obvious solution, you might be surprised to see that there are lots of ways this can be solved in JavaScript. For example, this article suggests 20 JavaScript ways to solve FizzBuzz!
The classic JavaScript solution though would look like this (using an old-fashioned for loop):

for (let i = 1; i <= 100; i++) {
   if (i % 3 === 0 && i % 5 === 0) console.log('FizzBuzz');
   else if (i % 5 === 0) console.log('Buzz');
   else if (i % 3 === 0) console.log('Fizz');
   else console.log(i);
}
Enter fullscreen mode Exit fullscreen mode

If you love one-liners, there is also a short version of it:

for (let i = 1; i <= 100; i++) console.log(i % 3 ? i % 5 ? i : 'Buzz' : i % 5 ? 'Fizz' : 'FizzBuzz')
Enter fullscreen mode Exit fullscreen mode

However, as our code is supposed to be read by humans (the machine will read it in any form), developers are generally advised against making the life of fellow programmers even more complicated than it already is.

While moving forward in my coding journey, I have attempted to implement a recursive version of FizzBuzz.

Recursion is the act of a function calling itself. Thus, recursion occurs any time a function calls itself inside itself, potentially creating an infinite loop Source.

A recursive function has 2 main ingredients: a base or exit condition and at least one recursive case. No exit condition would lead to an infinite loop.

A basic solution for a recursive FizzBuzz would be to create an inner recursive function that uses the initial value of the counter variable declared in the scope of the parent function. It represents a closure in a broader context:

You have a closure when a function accesses variables defined outside of it.

www.whatthefuck.is/closure/

In our case, the basic condition states: “if the parameter passed to the inner function (counter) is greater than the parameter passed to the main function - 100, exit the function”.

const fizzBuzz = (randomNum) => {
   let counter = 1;
   const func = (counter) => {
      if (counter > randomNum) return;

      if (counter % 5 === 0 && counter  % 3 === 0) console.log('FizzBuzz');
      else if (counter % 5 === 0) console.log('Buzz');
      else if (counter  % 3 === 0) console.log('Fizz');
      else console.log(counter);

      func(counter + 1);
   };
   func(counter);
}
fizzBuzz(100)
Enter fullscreen mode Exit fullscreen mode

However, this can be simplified by using default values of parameters (ES6 feature). So, the cleaner version would look like this:

const fizzBuzz = (randomNum, counter = 1) => {
   if (counter > randomNum) return;

   if (counter % 5 === 0 && counter  % 3 === 0) console.log('FizzBuzz');
   else if (counter % 5 === 0) console.log('Buzz');
   else if (counter  % 3 === 0) console.log('Fizz');
   else console.log(counter);

   fizzBuzz(randomNum, counter + 1);
};

fizzBuzz(100)
Enter fullscreen mode Exit fullscreen mode

The counter parameter is assigned a default value of 1. Thus, we don’t need the inner function anymore as its only role was to grab the initial counter value from the outer scope.

As a bonus, here is a recursive FizzBuzz running downwards:

const fizzBuzz = (randomNum) => {
   if (randomNum === 0) return;

   if (randomNum % 5 === 0 && randomNum % 3 === 0) console.log('FizzBuzz');
   else if (randomNum % 5 === 0) console.log('Buzz');
   else if (randomNum % 3 === 0) console.log('Fizz');
   else console.log(randomNum);
   fizzBuzz(randomNum - 1);
}

fizzBuzz(100)
Enter fullscreen mode Exit fullscreen mode

Recursion might be difficult to grasp at first. These simple examples of the classic programming puzzle were designed with an aim to make this topic a little bit clearer.

Cover photo by Céline Haeberly on Unsplash

Top comments (4)

Collapse
 
jonrandy profile image
Jon Randy 🎖️
console.log([...Array(100)].map((e,i)=>(++i%3?'':'fizz')+(i%5?'':'buzz')||i).join("\n"))
Enter fullscreen mode Exit fullscreen mode
Collapse
 
sabbin profile image
Sabin Pandelovitch • Edited

Another approach if you want to create an array is using the Array.from() method. This way you can combine the spread operator and the map together in one operation.

Array.from(
  { length: 100 },
  (o, i) => `${++i % 3 ? "" : "Fizz"}${i % 5 ? "" : "Buzz"}` || i
).forEach((el) => console.log(el));
Enter fullscreen mode Exit fullscreen mode
Collapse
 
jonrandy profile image
Jon Randy 🎖️

Needs fixing for "FizzBuzz"

Thread Thread
 
sabbin profile image
Sabin Pandelovitch

Indeed! I fixed the code in the comment. Didn't pay too much attention to the description