Creating a Range in JavaScript
Have you ever worked on a problem where you needed to make a list of all the numbers between two inputs and manipulate them in some sort of way? Recently, I found myself in just this predicament and thought that JavaScript would have a nice and easy built in function to make the process easier, like Ruby does. I was surprised to find that there is nothing similar to the simple built in Ruby Range method, and quite a bit of different ways to accomplish this in JavaScript.
In Ruby, you can build a new array from ranges by using the built in method .to_a
or the Array
method. If we need to create a range of years from 2010 to 2020, you would do it like (2010..2020).to_a
or Array (2010..2020)
. Inside the parenthesis we are giving Ruby two numbers and two dots, which Ruby interprets as creating an inclusive range from 2010 to 2020.
As seen above, and inclusive range creates an array for of all the numbers between and including the ones that invoked it.
Ruby also allows us to call the same two methods with three dots, which would create a new array that would exclude the specified highest value.
Calling our range method with three dots 2010...2020
creates an array for all the numbers from 2010–2019, and does not include 2020. As you can see, very easy and simple to create a range with specified parameters. In Ruby, the range functionality doesn’t only stop at numbers! Letters, conditionals, and even intervals can all use the built in range methods to produce some easy to read and compute functionality in our code.
Now, back to our JavaScript range issue. JavaScript does not have a two/three dot notation for creating ranges, however we could use the Ruby examples and create our own. In Ruby, the .to_a
and the Array
methods are built-in methods for creating new Arrays. So our JavaScript code could use the same foundation, and create a new Array to store all our numbers in. Next, using a for
loop, we could loop through the numbers and push them into the array until we reach our higher number and break the loop.
If we wanted to make our JavaScript code act like a Ruby exclusive range, our second argument in the for
loop would change to i < 2020
. While this is great, our use for continuously returning a range from 2010 to 2020 is rather limited. Our next change would be to write this to accept arguments, so that the code could perform a variety of tasks, and not just for this past decade. Writing this to be more dynamic would involve making a function that takes in two arguments for our range numbers.
In the above code, 2010
was changed to start
and 2020
to end
, allowing us to create ranges for whichever numbers we need. Now, our JavaScript range function is complete! And only a few more lines of code than our Ruby code…
Now, with our code above it super easy to read and understand what is happening. So let’s change it up a bit and make it more concise and complicated:
Above, instead of creating a new array, using a for
loop to iterate through our numbers, and pushing those numbers into the array to be returned once the loop is complete, we did the same process in one line.
Using the Array constructor, we specified the length of the return array as (end — start + 1)
. The newly created Array will have the correct length property, but nothing is actually in it. Trying to run .map() won’t work because there’s nothing to iterate over despite the length being the correct value.
To make the array contain elements we call the .fill() on it. Without any parameters it populates all the values of the array’s length, turning it from a weird empty array with a length to an array whose individual elements are each undefined
. This means we can iterate over them with map.
Lastly, .map() takes in a callback function which takes up to 3 parameters (previous value, index, and the original array) and fills in the array with the return value for each value. In our example, we use the callback function with the first two parameters because we need to use the index of the array for addition (which we cannot access the second parameter unless the first parameter is stated in the callback). Using a placeholder for the previous value _
, we completely ignore it and for each element in the array, we add the elements index to the start
argument.
In the example above, our code substituted with numbers would like like this: return Array(18 — 9 + 1).fill().map((_, index) => [9 + 0], [9 + 1], [9 + 2] ... [9 + 8], [9 + 9]))