One of the most common uses for the common JS for
loop must be to traverse the elements of an array. It might be to transform each element, filter a sub-set or convert the entire array into an entirely new data structure. This is probably the reason why the Array prototype acquired some super powers in ECMAScript 6 (ES 2015) in the form of some additional methods (map, filter, reduce, etc.) These methods make the code simpler to write (largely), understand and, being implemented inside the JS engine, has the potential to offer better performance.
Most of the new methods follow a common pattern in that they take a call-back function that is applied to each item in the array in turn. The majority of the methods return a brand new array (or another object) as the output. The call-back functions are typically one of three types:
- Transform: Converts the input item in to a new item
- Predicate: Applies some logic on the input item and returns a Boolean value as the result
- Reducer: Takes in two parameters, the second being the array item, the first being a 'running total' and produces an updated 'running total'.
Two additional points:
- I used the term 'running total' to describe the first parameter of the reducer but that is not to say it has to be a numeric value. It could be another array, an object or any value that gets passed from one cycle to the next.
- The call-backs actually take in more that 1 argument (or 2 arguments in the case of
reduce
). In addition to each item from the array it also takes the index of the item and the array itself.
But how can you test the call-backs without creating an array of test data. Here is where the adhocArray
function comes in useful, although I can also imagine scenarios where the function could be used in operational code.
Using an ad-hoc Array
As explained above, the majority of the time the call-backs need to operate on the items of an array. We can exercise the call-backs directly but ideally we still need a range of input values/objects.
The primary use case for the ad-hoc array is to exercise Pure functions, which are highly reusable, usually easy to test but often require additional inputs to make up for a lack of context. Pure functions operate entirely on their parameters and nothing outside of that including not changing the value of arguments supplied by reference. They only output via the return value which is deterministic and predictable from the input.
Implementation
I have experimented with a number of varieties of functions but the following is my preferred implementation to date. It works by first defining an Array of the required size but this only allocates space. The initial Array is expanding it out into another Array, which creates a populated Array. Finally the transform call-back function (default or supplied) is used to convert the index of each element of the array into a new array.
function adhocArray(length = 1, transform = _ => _) {
return [...Array(length).keys()].map(transform);
}
An arrow function could easily be used in place of a conventional function but this limits where the function can be declared. Through JS hoisting conventional functions can be declared at the bottom of a script and used before the declaration. This not true of arrow functions that have to be declared before they can be used.
Usage
The adhocArray
function enables us to execute a function a set number of times. We have the option of using the content of the array that has been especially created for the purpose. Now lets investigate its behaviour through a few experiments.
Default execution
console.log(adhocArray(6)); // [ 0, 1, 2, 3, 4, 5 ]
At first sight this might appear to be no different to creating an Array by just calling Array(6)
but that would create an array of 6 empty elements. Using adhocArray
we get back an array repopulated, by default with integers incrementing from zero.
Basic transform
const evenValues = i => (i + 1) * 2;
console.log(adhocArray(6, evenValues)); // [ 2, 4, 6, 8, 10, 12 ]
We can customise the array population using a supplied transform call-back that converts the default integer into whatever is required.
Basic transform with post processing (reduce-based sum)
const evenValues = i => (i + 1) * 2;
const sum = (total, inc) => total + inc;
console.log(adhocArray(6, evenValues).reduce(sum)); // 42
The array output can the be used for a variety of purposes but its original use case was to enable execution of a (call-back) function a set number of times; to render dummy data in a prototype screen for instance. In the above example I have used it to exercise an experimental reduce-based sum reducer.
Populating a 2-dimensional array
const multiplier = (_, __) => (_ + 1) * (__ + 1);
const timesTable = adhocArray(12, _ =>
adhocArray(12, __ => multiplier(_, __))
);
console.table(timesTable);
Combining adhocArray
can also produce a 2-dimensional data set. In this example I have used it to generate a 12x12 times table.
Bonus transforms
When creating a form that requires a day-of-week or month-of-year input it is not unusual to encounter a variable such as;
const DAYS_OF_WEEK = [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday'
];
But what if you need the list to be in another or multiple languages. We can use the JavaScript Intl namespace using the following utility functions to generate day and month names in long or short forms, in a variety of languages (defaulted to British English).
const shortDay = (day, lang = 'en-GB') =>
new Date(0, 0, day).toLocaleString(lang, { weekday: 'short' });
const longDay = (day, lang = 'en-GB') =>
new Date(0, 0, day).toLocaleString(lang, { weekday: 'long' });
const shortMonth = (mon, lang = 'en-GB') =>
new Date(0, mon, 1).toLocaleString(lang, { month: 'short' });
const longMonth = (mon, lang = 'en-GB') =>
new Date(0, mon, 1).toLocaleString(lang, { month: 'long' });
Here is a demonstration:
console.log(adhocArray(7, shortDay));
console.log(adhocArray(12, shortMonth));
/* Output - Default short day and month in GB English
[
'Sun', 'Mon',
'Tue', 'Wed',
'Thu', 'Fri',
'Sat'
]
[
'Jan', 'Feb', 'Mar',
'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sept',
'Oct', 'Nov', 'Dec'
]
*/
console.log(adhocArray(7, day => longDay(day, 'ga-IE')));
/* Output - Gaelic days of the week (in long form)
[
'Dé Domhnaigh',
'Dé Luain',
'Dé Máirt',
'Dé Céadaoin',
'Déardaoin',
'Dé hAoine',
'Dé Sathairn'
]
*/
console.log(adhocArray(12, mon => longMonth(mon, 'fr-FR')));
/* Output - French months in long form
[
'janvier', 'février',
'mars', 'avril',
'mai', 'juin',
'juillet', 'août',
'septembre', 'octobre',
'novembre', 'décembre'
]
*/
To Close
I am not convinced the adhocArray
has any real utility but I found it a useful and interesting exercise all the same. And besides it saves me another reason for writing boring for
loops.
Top comments (0)