Javascript Functional Programming: Producing Higher-Order Functions
I. Introduction
Functional programming is a paradigm of programming that emphasizes the use of functions as the primary building blocks of software. In contrast to imperative programming, which focuses on how to perform operations, functional programming focuses on what operations to perform. By using functions as the primary building blocks, functional programming allows for more modular, maintainable, and scalable code.
One of the key features of functional programming is higher-order functions. Higher-order functions are functions that take other functions as arguments or return functions as their results. They allow for powerful abstractions and expressive code that can be reused in many different contexts.
In this post, we’ll be exploring how to produce higher-order functions in Javascript. We’ll start by defining what higher-order functions are and why they are important in functional programming. Then, we’ll show you how to create your own higher-order functions in Javascript, using examples to illustrate the concepts. We’ll also demonstrate how to use higher-order functions in practical applications, including examples of how to use built-in higher-order functions like map, filter, and reduce to transform and manipulate data.
By the end of this post, you’ll have a better understanding of higher-order functions and how to use them in your own Javascript code. Whether you’re a beginner or an experienced developer, understanding functional programming and higher-order functions is an essential skill for building high-quality, maintainable software. So, let’s dive in and start exploring!
II. Higher-Order Functions
Higher-order functions are a key concept in functional programming, and they are an essential tool for building modular, reusable, and maintainable code. In this section, we’ll be exploring what higher-order functions are, why they are important in functional programming, and how to use them in Javascript.
In Javascript, a higher-order function is a function that takes one or more functions as arguments, and/or returns a function as its result. This may sound a bit abstract at first, but it’s a powerful concept that allows us to create more expressive and flexible code.
One of the primary benefits of higher-order functions is that they enable code reuse. By defining a function that takes in another function as an argument, we can create a function that performs a specific operation on any input that matches a given criteria. This means that we can write a function once, and then use it in many different contexts without having to repeat the code.
Another benefit of higher-order functions is that they enable us to create abstractions. We can define a function that takes in a complex function as an argument, and then use that function in our own code to simplify complex operations. This means that we can write code that is more expressive and easier to understand, even if we don’t fully understand the details of the underlying operations.
In the next section of this post, we’ll explore how to create higher-order functions in Javascript, and how to use them in practical applications. So, let’s dive in and start exploring the power of higher-order functions!
Examples of built-in higher-order functions in Javascript, like map, filter, and reduce
1. Map
The map
method is a built-in higher-order function in Javascript that creates a new array with the results of calling a provided function on every element in the original array. Here’s an example:Â
const numbers = [1, 2, 3, 4, 5];
const squaredNumbers = numbers.map(num => num * num);
console.log(squaredNumbers); // Output: [1, 4, 9, 16, 25]
In this example, we define an array of numbers and then use the map
method to create a new array called squaredNumbers
, where each element is the result of squaring the corresponding element in the original numbers
array.
2. Filter
The filter
method is another built-in higher-order function in Javascript that creates a new array with all elements that pass the test implemented by the provided function. Here’s an example:
const numbers = [1, 2, 3, 4, 5];
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // Output: [2, 4]
In this example, we define an array of numbers and then use the filter
method to create a new array called evenNumbers
, where each element is an even number from the original numbers
array.
3. Reduce
The reduce
method is a built-in higher-order function in Javascript that applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value. Here’s an example:
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum); // Output: 15
In this example, we define an array of numbers and then use the reduce
method to calculate the sum of all the elements in the numbers
array. The reduce
method takes two arguments: a callback function that defines the operation to perform on each element, and an initial value for the accumulator (in this case, 0).
These are just a few examples of the built-in higher-order functions in Javascript. In the next section, we’ll explore how to create our own higher-order functions in Javascript.
III. Producing Higher-Order Functions
In the previous section, we explored what higher-order functions are and why they are important in functional programming. Now, we’ll dive deeper and explore how to create your own higher-order functions in Javascript.
Creating your own higher-order functions can be incredibly useful in Javascript, as it allows you to create code that is more modular, maintainable, and reusable. By creating functions that take in other functions as arguments, or return functions as their results, you can create code that is more expressive and flexible, and that can be used in many different contexts.
In this section, we’ll explore how to create higher-order functions in Javascript. We’ll start by looking at examples of functions that take other functions as arguments, and show you how to write them step-by-step. Then, we’ll move on to functions that return other functions as their results, and explore the concepts involved in creating these functions.
By the end of this section, you’ll have a better understanding of how to create your own higher-order functions in Javascript, and how to use them in practical applications. So, let’s dive in and start exploring how to produce higher-order functions in Javascript!
A. How to create higher-order functions in Javascript
Creating your own higher-order functions in Javascript is a powerful way to build modular, maintainable, and reusable code. In this section, we’ll explore how to create higher-order functions that take other functions as arguments, and functions that return other functions as their results.
Creating Functions that Take Other Functions as Arguments
To create a function that takes another function as an argument, you simply define the function with the desired argument name, and then pass in the function as an argument when the higher-order function is called.
Let’s start theapplyOperation
function which is a very basic function. This function allows you to pass in an operation function along with two numbers, and it will apply the operation on those numbers and return the result. If no operation function is provided, it defaults to an empty function, and if no numbers are provided, it defaults to 0
and 2
.
Here is how you can implement this applyOperation
 function:Â
const applyOperation = (operation = () => {}, num1 = 0, num2 = 2) => operation(num1, num2);
const add = (num1 = 0, num2 = 1) => num1 + num2;
const multiply = (num1 = 0, num2 = 1) => num1 * num2;
const sum = applyOperation(add, 5, 3); // Output: 8
const product = applyOperation(multiply, 5, 3); // Output: 15
Next, let’s create apromisify
function. Here is an implementation of ourpromisify
function:Â
/**
* @name promisify
* @function
*
* @param {Function|Object} fn the function or object to be promisified
*
* @description promisified functions or objects
* @return {Function|Object} fn, the promisified function
*
*/
const promisify = (fn = () => {}) => (...args) =>
new Promise((resolve, reject) =>
fn(...args, (error, data) => error ? reject(error) : resolve(data)));
The
promisify
function takes a callback-style functionfn
as its input parameter.It returns a new function that accepts any number of arguments
(...args)
.This new function creates a new Promise using the
Promise
constructor. This Promise resolves with thedata
object if thefn
function executes without error, or rejects with theerror
object if thefn
function encounters an error.The
fn
function is called with the given arguments (...args
) and an additional callback function that takes anerror
object and thedata
object as its two arguments.If the
error
object is truthy, the Promise is rejected with theerror
object.If the
error
object is falsy, the Promise is resolved with thedata
object.
Our promisify
function allows you to convert a callback-style asynchronous function into a Promise-based asynchronous function. It does this by wrapping the original function in a new function that returns a Promise and then calling the original function with the given arguments along with a callback function that resolves or rejects the Promise based on the result of the original function.
Here is an example of how to use our promisify
function:
Next, let’s create ademethodize
function. Here is an implementation of ourdemthodize
function:Â
/**
* @name demethodize
* @function
*
* @param {Function|Object} fn the function to bind to object method
*
* @description plucks off a method from ANY object and makes that method a completely independent standalone reusable function.
*
* For instance, if I wanted to make Array.prototype.map method an independent standalone reusable function, I would do something like this: const myArrayMap = pluckOff(Array.prototype.map). Then I would use it like this:
*
* const array = [1,2,3,4,5]; const result = myArrayMap(array, x => x * 2); result = [2,4,6,8,10]
*
* @return {Function|Object} fn.bind(...args)(), the completely independent standalone reusable function
*
*/
const demethodize = (fn = () => {}) => (...args)=> fn.bind(...args)();
The
demethodize
function takes a method functionfn
as its input parameter.It returns a new function that accepts any number of arguments
(...args)
.This new function creates a bound function by calling
fn.bind(...args)
. Thebind()
method creates a new function with the same body as the originalfn
function, but with itsthis
value bound to the object passed as the first argument. In this case,...args
represents the object that the methodfn
function would normally be called on.The new bound function is immediately called with no arguments
()
using the parentheses at the end of the line, and its return value is returned by the outer function.
Our demethodize
 function allows you to “demethodize” a method function so that it can be called separately from an object context. It does this by creating a bound function using fn.bind(...args)
and immediately calling it with no arguments ()
. The return value of the bound function is then returned by the outer function.
Next, let’s create a promisify
function. Here is an implementation of ourpromisify
function:Â
/**
* @name demethodizeConstruct
* @function
*
* @param {Function|Object} Source The object to demethodize
* @param {Function|Object} Destination The object to methodify
*
* @description Methodifies a destination object with all the methods on the prototype of the source object
*
* @return {Function|Object} The methodified object
*
*/
const demethodizeConstruct = (Source = {}, Destination = {} ) => {
for(let method of Object.getOwnPropertyNames(Source.prototype)){
Destination[method] = demethodize(Source.prototype[method])
}
return Destination;
}
The
demethodizeConstruct
function takes two parameters: theSource
constructor function whose prototype methods need to be demethodized, and theDestination
object where the demethodized functions will be added.It loops through all the prototype methods of the
Source
constructor function using afor..of
loop and theObject.getOwnPropertyNames
method.For each prototype method, it creates a new function using the
demethodize
function, passing in the method as thefn
parameter and an empty object{}
as thethisArg
parameter.It adds the new demethodized function to the
Destination
object with the same method name.The
Destination
object with the demethodized functions added to it is returned.
Our demethodizeConstruct
 function allows you to demethodize all the prototype methods of a constructor function and add them to a target object. It does this by looping through all the prototype methods of the Source
constructor function, using the demethodize
function to create a new demethodized function for each method, and adding the new demethodized function to the Destination
object. The Destination
object with the demethodized functions added to it is then returned.
Next, let’s create afindOptimum
function. Here is an implementation of our findOptimum
 function:Â
/**
* @name findOptimum
* @function
*
* @param {Function|Object} fn the function
*
* @description creates an optimization function
* @return {Function|Object} The optimization function
*
*/
const findOptimum = (fn = () => {}) => (array = []) => Array.isArray(array) ? array.reduce(fn): null;
The
findOptimum
function takes a functionfn
as its input parameter.It returns a new function that takes one parameter
array
.If
array
is an array, the new function calls thereduce()
method onarray
, passing in thefn
function as the first argument. Thereduce()
method applies thefn
function to each element of the array and returns a single value that represents the optimum value. Thereduce()
method can be used to find the maximum or minimum value in an array, for example.If
array
is not an array, the new function returnsnull
.
Our findOptimum
function allows you to find the optimum value in an array by applying a comparison function to all the elements of the array. It does this by returning a new function that takes an array as its parameter and uses the reduce()
method to apply the fn
function to all the elements of the array and return the optimum value. If the input parameter is not an array, it returns null
.
Next, let’s create a callFirstOnlyNTimes
function. Here is an implementation of our callFirstOnlyNTimes
 function:Â
/**
* @name callFirstOnlyNTimes
* @function
*
* @param {Function|Object} f the function to be called only n times
* @param {Function|Object} g the function to be called as many times as left after f() is called n times
* @param {Number} n number of time the function f() should be called
*
* @description creates a function that calls and runs the first argument function f() n times and only n times no matter how many times the function is called or used in the loop. It calls f() exactly n times and the rest of the times it calls g(). For instance if n = 1 and the function is called 200 times, it would call or execute f() only once and g() 199 times. If n = 5 and the function is called 200 times, it would call or execute f() exactly 5 times and g() 195 times.
*
* @return {Function|Object} a function that calls fn() only n times and g() afterward
*
*/
const callFirstOnlyNTimes = (f = () => {}, g = () => {}, n = 1) => {
let done = false
return (...args) => {
if (!done) {
done = true
if (typeof n !== 'number' || n % 1 !== 0) {
f(...args)
} else {
for (let i = 1; i <= Math.abs(n); i++) {
f(...args)
}
}
} else {
g(...args)
}
}
}
The
callFirstOnlyNTimes
function takes three parameters:f
,g
, andn
.It initializes a variable
done
tofalse
.It returns a new function that takes any number of arguments (
...args
).The returned function checks if
done
isfalse
. Ifdone
isfalse
, the returned function setsdone
totrue
and checks the value ofn
.If
n
is not a whole number, the returned function callsf
with the given arguments (...args
).If
n
is a whole number, the returned function callsf
with the given arguments (...args
)n
times using afor
loop.If
done
istrue
, the returned function callsg
with the given arguments (...args
).The
f
function will be called only the firstn
times the returned function is called, after which theg
function will be called every time the returned function is called.
OurcallFirstOnlyNTimes
function allows you to specify a function f
that will be called only the first n
times the returned function is called, and a function g
that will be called every time after that. It does this by returning a new function that uses a flag variable done
to determine whether f
or g
should be called. If done
is false
, the returned function calls f
the first n
times it is called, and then sets done
to true
and calls g
every time after that.
Next, let’s create a callOnlyNTimes
function. Here is an implementation of our
callOnlyNTimes
function:Â
/**
* @name callOnlyNTimes
* @function
*
* @param {Function|Object} fn the function to be called only n times
* @param {Number} n number of time the function f() should be called
*
* @description creates a function that calls and runs the function f() n times and only n times no matter how many times the function is called or used in the loop. It calls f() exactly n times. For instance if n = 1 and the function is called 200 times, it would call or execute f() only once (no more than once). If n = 5 and the function is called 200 times, it would call or execute f() exactly 5 times and no more than 5 times.
*
* @return {Function|Object} a function that calls fn() only n times
*
*/
const callOnlyNTimes = (fn = () => {}, n = 1) => {
let done = false
return (...args) => {
if (!done) {
done = true
for (let i = 0; i < Math.abs(n); i++) {
fn(...args)
}
}
}
}
The
callOnlyNTimes
function takes two parameters:fn
andn
.It initializes a variable
done
tofalse
.It returns a new function that takes any number of arguments (
...args
).The returned function checks if
done
isfalse
. Ifdone
isfalse
, the returned function setsdone
totrue
and callsfn
n
times using afor
loop.The
fn
function will be called only the firstn
times the returned function is called.
OurcallOnlyNTimes
function allows you to specify a function fn
that will be called only the first n
times the returned function is called. It does this by returning a new function that uses a flag variable done
to determine whether fn
should be called. If done
is false
, the returned function sets done
to true
and calls fn
n
times using a for
loop. After the first n
times the returned function is called, the fn
function will not be called again.
Next, let’s create a billOnceAndOnlyOnce
 function. Here is an implementation of ourbillOnceAndOnlyOnce
function:Â
/**
* @name billOnceAndOnlyOnce
* @function
*
* @param {Function|Object} bill the function to call for billing
* @param {Function|Object} dontBill the function to call to avoid billing
*
* @description creates a function that is called and runs only onces no matter how many times the function is called or used in the loop. For instance if the function is called 200 times, it would be called or executed only the first round (no more than once); that is it would 1 time and not run the rest of 199 times.
*
* @return {Function|Object} a function that bills only once not matter what
*
*/
const billOnceAndOnlyOnce = (bill = () => {}, dontBill = () => {}) => {
let timeToBill = bill
return (...args) => {
let result = timeToBill(...args)
timeToBill = dontBill
return result
}
}
The
billOnceAndOnlyOnce
function takes two parameters:bill
anddontBill
.It initializes a variable
timeToBill
tobill
.It returns a new function that takes any number of arguments (
...args
).The returned function calls
timeToBill
with the given arguments (...args
) and stores the result in a variableresult
.The returned function then sets
timeToBill
todontBill
.Finally, the returned function returns the
result
.The
bill
function will be called only the first time the returned function is called, and thedontBill
function will be called every time after that.
OurbillOnceAndOnlyOnce
function allows you to specify a function bill
that will be called only the first time the returned function is called, and a function dontBill
that will be called every time after that. It does this by returning a new function that uses a variable timeToBill
to keep track of which function should be called, and then sets timeToBill
to dontBill
after the first call to the returned function.
Next, let’s create a inputsValid
function. We will use this mostly as a helper function to help perform some validations for our upcoming function. Here is an implementation of ourinputsValid
 function:Â
/**
* @name inputsValid
* @function
*
* @param {Function} array the array to validate
* @param {Function} fn the call back function to validate
* @param {Number} flat arr flattening depth to validate
*
* @description validates inputs
*
* @return {Boolean} true if inputs are valid and false if inputs are invalid
*
*/
const inputsValid = (array = [], fn = () => {}, flat = 1) => {
if (!Array.isArray(array)) return false
if (typeof fn !== 'function') return false;
if (typeof flat !== 'number' || flat < 0 || (flat % 1 !== 0 && flat !== Infinity)) return false;
return true
}
The
inputsValid
function takes three parameters:array
,fn
, andflat
.It checks if
array
is an array by using theArray.isArray()
method. Ifarray
is not an array, the function returnsfalse
.It checks if
fn
is a function by using thetypeof
operator. Iffn
is not a function, the function returnsfalse
.It checks if
flat
is a whole number orInfinity
by using thetypeof
operator and the modulo operator (%
). Ifflat
is not a whole number orInfinity
, the function returnsfalse
.If all three input parameters pass the validation checks, the function returns
true
. Otherwise, it returnsfalse
.
Our inputsValid
function validates whether the input parameters array
, fn
, and flat
are valid or not. It does this by checking whether array
is an array, whether fn
is a function, and whether flat
is a whole number or Infinity
. If all input parameters pass the validation checks, the function returns true
. Otherwise, it returns false
.
Next, let’s create a none
function. Here is an implementation of our
none
 function:Â
/**
* @name none
* @function
*
* @param {Array|Object} array the array to filter
* @param {Function|Object} fn the predicate
* @param {Number} flat the array to filter flattening depth
*
* @description Checks if none of the elements of the array satisfies the predicate
*
* @return {Boolean} True if none of the elements of the array satisfies the predicate. False otherwise
*
*/
const none = (array = [], fn = () => false, flat = 0) => inputsValid(array, fn, flat) ? array.flat(flat).every(v => !fn(v)) : false;
The
none
function takes three parameters:array
,fn
, andflat
.It checks whether the input parameters
array
,fn
, andflat
are valid by calling theinputsValid
function. If any of the input parameters fail the validation checks, the function returnsfalse
.If all input parameters pass the validation checks, the function flattens the
array
to the specified depth using theflat()
method.It then uses the
every()
method to check whether none of the elements in the flattenedarray
pass the test implemented by thefn
function.If none of the elements pass the test, the function returns
true
. Otherwise, it returnsfalse
.
Ournone
function checks whether none of the elements in array
pass the test implemented by the fn
function. It does this by validating the input parameters array
, fn
, and flat
, flattening the array
to the specified depth, and then using the every()
method to check whether none of the elements in the flattened array
pass the test implemented by the fn
function. If none of the elements pass the test, the function returns true
. Otherwise, it returns false
.
Next, let’s create a forEachAsync
function. Here is an implementation of ourforEachAsync
function:Â
/**
* @name forEachAsync
* @function
*
* @param {Array|Object} array the array to loop over
* @param {Function|Object} fn the callback function
* @param {Number} flat the array to loop over flattening depth
*
* @description asynchronously loops an array
*
* @return {Promise} A promise if promise is fulfilled and successfull
*
*/
const forEachAsync = (array = [], fn = () => false, flat = 0) => inputsValid(array, fn, flat) ? array.flat(flat).reduce((promise, value) => promise.then(() => fn(value)), Promise.resolve()): undefined
The
forEachAsync
function takes three parameters:array
,fn
, andflat
.It checks whether the input parameters
array
,fn
, andflat
are valid by calling theinputsValid
function. If any of the input parameters fail the validation checks, the function returnsundefined
.If all input parameters pass the validation checks, the function flattens the
array
to the specified depth using theflat()
method.It then uses the
reduce()
method to iterate over each element of the flattenedarray
asynchronously.For each element of the flattened
array
, thefn
function is called usingPromise.then()
. This ensures that the elements are processed in the correct order.The
reduce()
method returns a Promise that resolves when all elements ofarray
have been processed.
OurforEachAsync
function iterates over each element of array
asynchronously and calls the fn
function for each element. It does this by validating the input parameters array
, fn
, and flat
, flattening the array
to the specified depth, and then using the reduce()
method to iterate over each element of the flattened array
asynchronously. The function returns a Promise that resolves when all elements of array
have been processed.
Next, let’s create a mapAsync
function. Here is an implementation of ourmapAsync
function:Â
/**
* @name mapAsync
* @function
*
* @param {Array|Object} array the array to map
* @param {Function|Object} fn the callback function
* @param {Number} flat the array to map flattening depth
*
* @description asynchronously maps an array
*
* @return {Promise} A promise if promise is fulfilled and successfull
*
*/
const mapAsync = (array = [],fn = () => [], flat = 0) => inputsValid(array, fn, flat)? Promise.all(array.flat(flat).map(fn)): [];
The
mapAsync
function takes three parameters:array
,fn
, andflat
.It checks whether the input parameters
array
,fn
, andflat
are valid by calling theinputsValid
function. If any of the input parameters fail the validation checks, the function returns an empty array[]
.If all input parameters pass the validation checks, the function flattens the
array
to the specified depth using theflat()
method.It then uses the
map()
method to apply thefn
function to each element of the flattenedarray
.The
map()
method returns an array of Promises, which resolve to the results of applying thefn
function to each element ofarray
.The
Promise.all()
method is used to wait for all Promises to resolve before returning a single Promise that resolves to an array of the results of applying thefn
function to each element ofarray
.
OurmapAsync
function applies the fn
function to each element of array
and returns a Promise that resolves to an array of the results. It does this by validating the input parameters array
, fn
, and flat
, flattening the array
to the specified depth, and then using the map()
method to apply the fn
function to each element of the flattened array
. Finally, it returns a Promise that resolves to an array of the results. If any of the input parameters fail the validation checks, the function returns an empty array []
.
Next, let’s create a filterAsync
function. Here is an implementation of ourfilterAsync
 function:Â
/**
* @name filterAsync
* @function
*
* @param {Array|Object} array the array to filter
* @param {Function|Object} fn the callback function
* @param {Number} flat the array to filter flattening depth
*
* @description asynchronously filters an array
*
* @return {Promise} A promise if promise is fulfilled and successfull
*
*/
const filterAsync = (array = [], fn = () => [], flat = 0) => inputsValid(array, fn, flat) ? mapAsync(fn, flat).then(array => array.flat(flat).filter((v, i) => Boolean(array[i]))): []
The
filterAsync
function takes three parameters:array
,fn
, andflat
.It checks whether the input parameters
array
,fn
, andflat
are valid by calling theinputsValid
function. If any of the input parameters fail the validation checks, the function returns an empty array[]
.If all input parameters pass the validation checks, the function uses the
mapAsync()
function to apply thefn
function to each element of the flattenedarray
.The
mapAsync()
function returns a Promise that resolves to an array of the results of applying thefn
function to each element of the flattenedarray
.The Promise returned by
mapAsync()
is then used to filter the originalarray
. If the Promise resolves to an array of values that are truthy, then the corresponding element in the originalarray
is included in the result array. Otherwise, the element is excluded.Finally, the Promise is resolved to the filtered array.
OurfilterAsync
function filters array
using the fn
function and returns a Promise that resolves to an array of the elements that pass the test. It does this by validating the input parameters array
, fn
, and flat
, using the mapAsync()
function to apply the fn
function to each element of the flattened array
, and then filtering the original array
using the Promise returned by mapAsync()
. If any of the input parameters fail the validation checks, the function returns an empty array []
.
Next, let’s create a reduceAsync
function. Here is an implementation of ourreduceAsync
function:Â
/**
* @name reduceAsync
* @function
*
* @param {Array|Object} array the array to reduce
* @param {Function|Object} fn the callback function
* @param {Number} flat the array to reduce flattening depth
*
* @description asynchronously reduces an array
*
* @return {Promise} A promise if promise is fulfilled and successfull
*
*/
const reduceAsync = (array =[], fn = () => {}, init, flat = 0) => inputsValid(array, fn, flat)
? Promise.resolve(init).then(accumulator => this.forEachAsync(array.flat(flat), async (v, i) => {
accumulator = fn(accumulator, v, i)
}).then(() => accumulator))
: 0;
The
reduceAsync
function takes four parameters:array
,fn
,init
, andflat
.It checks whether the input parameters
array
,fn
, andflat
are valid by calling theinputsValid
function. If any of the input parameters fail the validation checks, the function returns0
.If all input parameters pass the validation checks, the function flattens the
array
to the specified depth using theflat()
method.It then uses the
forEachAsync()
function to iterate over each element of the flattenedarray
asynchronously.For each element of the flattened
array
, thefn
function is called using thePromise.then()
method to update the accumulator value asynchronously.The
reduceAsync()
function returns a Promise that resolves to the final value of the accumulator after all elements ofarray
have been processed by thefn
function.
OurreduceAsync
function reduces the array
using the fn
function and returns a Promise that resolves to the final value of the accumulator. It does this by validating the input parameters array
, fn
, and flat
, flattening the array
to the specified depth, and then using the forEachAsync()
function to iterate over each element of the flattened array
asynchronously. Finally, it returns a Promise that resolves to the final value of the accumulator. If any of the input parameters fail the validation checks, the function returns 0
.
Next, let’s create afiltered
function. Here is an implementation of ourfiltered
function:Â
/**
* @name filter
* @function
*
* @param {Array|Object} array the array to filter
* @param {Function|Object} fn the call back function
* @param {Number} flat the array to filter flattening depth
*
* @description filters an array
*
* @return {Array|Object} The filtered array
*
*/
const filtered = (array = [], fn = () => [], flat = 1) => inputsValid(array, fn, flat) ? array.flat(flat).filter(x => fn(x)) : [];
The
filtered
function takes three parameters:array
,fn
, andflat
.It checks whether the input parameters
array
,fn
, andflat
are valid by calling theinputsValid
function. If any of the input parameters fail the validation checks, the function returns an empty array[]
.If all input parameters pass the validation checks, the function flattens the
array
to the specified depth using theflat()
method.It then uses the
filter()
method to filter the flattenedarray
based on thefn
function.The
filter()
method returns a new array containing the elements ofarray
that pass the test implemented by thefn
function.The
filtered()
function returns the new filtered array.
Ourfiltered
function filters the array
using the fn
function and returns a new array containing the elements that pass the test. It does this by validating the input parameters array
, fn
, and flat
, flattening the array
to the specified depth, and then using the filter()
method to filter the flattened array
. If any of the input parameters fail the validation checks, the function returns an empty array []
.
Next, let’s create a filterItems
function. Here is an implementation of ourfilterItems
function:Â
/**
* @name filterItems
* @function
*
* @param {Array|Object} array the array to filter
* @param {String} query any fitlering query
*
* @description reads a query and filter arrays according to the query
*
* @return {Array} The query filtered array
*
*/
const filterItems = (query, array = []) => Array.isArray(array) ? array.filter(el => el.toLowerCase().indexOf(query.toLowerCase()) !== -1): [];
The
filterItems
function takes two parameters:query
andarray
.It checks whether the input parameter
array
is an array by calling theArray.isArray()
method. Ifarray
is not an array, the function returns an empty array[]
.If
array
is an array, the function uses thefilter()
method to create a new array containing the elements ofarray
that contain thequery
string.The
filter()
method iterates over each element ofarray
and calls a callback function for each element. The callback function tests whether the element contains thequery
string using theindexOf()
method. If thequery
string is found in the element, the callback function returnstrue
, which includes the element in the new array. Otherwise, the callback function returnsfalse
, which excludes the element from the new array.The
filterItems()
function returns the new array containing the elements ofarray
that contain thequery
string.
OurfilterItems
function filters the array
to create a new array containing the elements that contain the query
string. It does this by using the filter()
method to create a new array containing the elements of array
that contain the query
string. If array
is not an array, the function returns an empty array []
.
Next, let’s create asome
function. Here is an implementation of oursome
function:Â
/**
* @name some
* @function
*
* @param {Array} array The input array to check
* @param {Function} fn The predicate function to call when
* @param {Number} flat the array to check flattening depth
*
* @description checks an array according to the thruthiness of the predicate
*
* @return {Boolean} true if at least one of the array items for which the predicate is true if found. false otherwise
*
*/
const some = (array = [], fn = () => false, flat = 0) => inputsValid(array, fn, flat) ? array.flat(flat).reduce((x, y) => x || fn(y), false) : false;
The
some
function takes three parameters:array
,fn
, andflat
.It checks whether the input parameters
array
,fn
, andflat
are valid by calling theinputsValid
function. If any of the input parameters fail the validation checks, the function returnsfalse
.If all input parameters pass the validation checks, the function flattens the
array
to the specified depth using theflat()
method.It then uses the
reduce()
method to iterate over each element of the flattenedarray
and test it using thefn
function.For each element of the flattened
array
, thefn
function is called to test whether the element passes the test.If at least one element in the
array
passes the test implemented by thefn
function, thereduce()
method returnstrue
. Otherwise, it returnsfalse
.The
some()
function returns the boolean value returned by thereduce()
method.
Oursome
function tests thearray
using thefn
function and returns a boolean value that indicates whether at least one element in the array
passes the test. It does this by validating the input parameters array
, fn
, and flat
, flattening the array
to the specified depth, and then using the reduce()
method to iterate over each element of the flattened array
and test it using the fn
function. If any of the input parameters fail the validation checks, the function returns false
.
Next, let’s create aevery
function. Here is an implementation of ourevery
function:Â
/**
* @name every
* @function
*
* @param {Array} array the array to check
* @param {Function} fn the predicate function
* @param {Number} flat the array to filter flattening depth
*
* @description checks an array according to the thruthiness of the predicate
*
* @return {Boolean} true if each one of the array items for which the predicate is true if found. false otherwise
*
*/
const every = (array = [], fn = () => false, flat = 0, result = []) => {
if(inputsValid(arr, fn, falt)){
array.flat(flat).reduce((x, y) => (x === false && fn(y) ? result.push(y) : result.pop()), false);
return result.length === array.flat(flat).length ? true : false;
}else{
return false;
}
}
The
every
function takes four parameters:array
,fn
,flat
, andresult
.It checks whether the input parameters
array
,fn
, andflat
are valid by calling theinputsValid
function. If any of the input parameters fail the validation checks, the function returnsfalse
.If all input parameters pass the validation checks, the function flattens the
array
to the specified depth using theflat()
method.It then uses the
reduce()
method to iterate over each element of the flattenedarray
and test it using thefn
function.For each element of the flattened
array
, thefn
function is called to test whether the element passes the test.If an element passes the test, it is added to the
result
array using thepush()
method.If an element does not pass the test, it is removed from the
result
array using thepop()
method.If all elements in the
array
pass the test implemented by thefn
function, theresult
array will be equal to the flattenedarray
, and the function returnstrue
. Otherwise, it returnsfalse
.The
every()
function returns the boolean value returned by thereduce()
method.
Ourevery
function tests the array
using the fn
function and returns a boolean value that indicates whether all elements in the array
pass the test. It does this by validating the input parameters array
, fn
, and flat
, flattening the array
to the specified depth, and then using the reduce()
method to iterate over each element of the flattened array
and test it using the fn
function. If any of the input parameters fail the validation checks, the function returns false
.
Next, let’s create aforEach
function. Here is an implementation of ourforEach
function:Â
/**
* @name forEach
* @function
*
* @param {Array} array the input array
* @param {Function} fn the predicate function
* @param {Number} flat the array to loop over flattening depth
*
* @description performs fn() operation for each of the array elements
*
* @return {Function|Object} the resulting object or array or element from the fn() operation
*
*/
const forEach = (array = [], fn = () => false, flat = 0) => {
if(inputsValid(array, fn, flat)){
for (let i = 0; i < array.flat(flat).length; i++) {
fn(array.flat(flat)[i],i,array);
}
}else{
return undefined;
}
};
The
forEach
function takes three parameters:array
,fn
, andflat
.It checks whether the input parameters
array
,fn
, andflat
are valid by calling theinputsValid
function. If any of the input parameters fail the validation checks, the function returnsundefined
.If all input parameters pass the validation checks, the function flattens the
array
to the specified depth using theflat()
method.It then uses a
for
loop to iterate over each element of the flattenedarray
.For each element of the flattened
array
, thefn
function is called with the current element as its argument.The function does not return a value.
OurforEach
function iterates over the array
using a for
loop and calls the fn
function for each element of the array
. It does this by validating the input parameters array
, fn
, and flat
, flattening the array
to the specified depth, and then using a for
loop to iterate over each element of the flattened array
and call the fn
function with the current element as its argument. If any of the input parameters fail the validation checks, the function returns undefined
.
Next, let’s create afilter
function. Here is an implementation of ourfilter
function:Â
/**
* @name filter
* @function
*
* @param {Array} array the array to filter
* @param {Function} fn the predicate function
* @param {Number} flat the array to filter flattening depth
*
* @description filters an array according to the thruthiness of the predicate
*
* @return {Array} the resulting array
*
*/
const filter = (array = [], fn = () => false, flat = 0, result = []) => {
if(inputsValid(array, fn, flat)){
for (let i = 0; i < this.flat(flat).length; i++) {
fn(array.flat(flat)[i],i,array) ? result.push(array.flat(flat)[i]) : [];
}
return result.length > 0 ? result : [];
}else{
return [];
}
};
The
filter
function takes four parameters:array
,fn
,flat
, andresult
.It checks whether the input parameters
array
,fn
, andflat
are valid by calling theinputsValid
function. If any of the input parameters fail the validation checks, the function returns an empty array[]
.If all input parameters pass the validation checks, the function flattens the
array
to the specified depth using theflat()
method.It then uses a
for
loop to iterate over each element of the flattenedarray
.For each element of the flattened
array
, thefn
function is called with the current element, index and the entirearray
as arguments, to test whether the element passes the test.If an element passes the test implemented by the
fn
function, it is added to theresult
array using thepush()
method.If an element does not pass the test, it is not added to the
result
array.The
filter()
function returns theresult
array if it contains any elements that passed the test. Otherwise, it returns an empty array[]
.
Ourfilter
function filters the array
using the fn
function and returns an array that contains the elements of array
that pass the test. It does this by validating the input parameters array
, fn
, and flat
, flattening the array
to the specified depth, and then using a for
loop to iterate over each element of the flattened array
and call the fn
function with the current element, index and the entire array
as arguments. If an element passes the test, it is added to the result
array, which is then returned by the function if it contains any elements that passed the test. If any of the input parameters fail the validation checks, the function returns an empty array []
.
Next, let’s create a flatten
function. Here is an implementation of ourflatten
function:Â
/**
* @name flatten
* @function
*
* @param {Array} array the array to flatten
*
* @description filten an array to whatsover depth or level it has
*
* @return {Array} the resulting flattened array
*
*/
const flatten = (array =[], result = []) => {
array.forEach(el => (Array.isArray(el) ? result.push(...flatten(el)) : result.push(el)));
return result;
};
The
flatten
function takes two parameters:array
andresult
.The function first checks whether the input parameter
array
is an array using theArray.isArray()
method. Ifarray
is not an array, it returns theresult
array.If
array
is an array, the function uses theforEach()
method to iterate over each element ofarray
.For each element of
array
, theflatten
function checks whether it is an array using theArray.isArray()
method.If the element is an array, the
flatten
function calls itself recursively, passing the element as thearray
parameter and theresult
array as theresult
parameter.If the element is not an array, the
flatten
function adds it to theresult
array using thepush()
method.The
flatten()
function returns theresult
array after all elements ofarray
have been flattened.
Ourflatten
function flattens a multi-dimensional array
to a single depth by recursively calling itself on each element of the array
that is an array, and adding all non-array elements to the result
array using the push()
method. It does this by checking whether the input parameter array
is an array, and then iterating over each element of array
using the forEach()
method. If an element is an array, the flatten
function calls itself recursively on that element, passing the result
array as the result
parameter. If an element is not an array, it is added to the result
array using the push()
method. Finally, the flatten()
function returns the result
array after all elements of array
have been flattened.
Next, let’s create afindIndex
function. Here is an implementation of ourfindIndex
function:Â
/**
* @name findIndex
* @function
*
* @param {Array} array the input array
* @param {Function} fn the predicate function
* @param {Number} flat The input array flattening depth
*
* @description find the index of an array element
*
* @return {Array} the resulting array element
*
*/
const findIndex = (array = [], fn = () => false, flat = 0) => inputsValid(array, fn, flat) ? array.flat(flat).reduce((x, y, z) => (x === -1 && fn(y) ? z : x), -1): undefined;
The
findIndex
function takes three parameters:array
,fn
, andflat
.It checks whether the input parameters
array
,fn
, andflat
are valid by calling theinputsValid
function. If any of the input parameters fail the validation checks, the function returnsundefined
.If all input parameters pass the validation checks, the function flattens the
array
to the specified depth using theflat()
method.It then uses the
reduce()
method to iterate over each element of the flattenedarray
.For each element of the flattened
array
, thefn
function is called with the current element, index and the entirearray
as arguments, to test whether the element passes the test.If an element passes the test implemented by the
fn
function, thereduce()
method returns the index of that element, which is then returned by thefindIndex()
function.If no element passes the test, the
reduce()
method returns-1
, which is then returned by thefindIndex()
function.The
findIndex()
function returnsundefined
if any of the input parameters fail the validation checks.
OurfindIndex
function searches the array
using the fn
function and returns the index of the first element in array
that passes the test. It does this by validating the input parameters array
, fn
, and flat
, flattening the array
to the specified depth, and then using the reduce()
method to iterate over each element of the flattened array
and call the fn
function with the current element, index and the entire array
as arguments. If an element passes the test, the index of that element is returned by the reduce()
method, which is then returned by the findIndex()
function. If no element passes the test, the reduce()
method returns -1
, which is then returned by the findIndex()
function. If any of the input parameters fail the validation checks, the function returns undefined
.
Next, let’s create a map
function. Here is an implementation of ourmap
function:Â
/**
* @name map
* @function
*
* @param {Array} array the array to map
* @param {Function} fn The predicate function
* @param {Number} flat The inpurt array flattening depth
*
* @description maps each element with the resulting operation of the callback function
*
* @return {Array} The resulting array
*
*/
const map = (array = [], fn = () => [], flat = 0) => inputsValid(array, fn, flat) ? array.flat(flat).reduce((x, y) => x.concat(fn(y)), []) : [];
The
map
function takes three parameters:array
,fn
, andflat
.It checks whether the input parameters
array
,fn
, andflat
are valid by calling theinputsValid
function. If any of the input parameters fail the validation checks, the function returns an empty array[]
.If all input parameters pass the validation checks, the function flattens the
array
to the specified depth using theflat()
method.It then uses the
reduce()
method to iterate over each element of the flattenedarray
.For each element of the flattened
array
, thefn
function is called with the current element as an argument, and the result is concatenated to the accumulatingx
array.The
reduce()
method returns the accumulatedx
array after all elements of the flattenedarray
have been mapped.The
map()
function returns the result of thereduce()
method.The
map()
function returns an empty array[]
if any of the input parameters fail the validation checks.
Ourmap
function maps the array
using the fn
function and returns a new array that contains the result of applying the fn
function to each element of array
. It does this by validating the input parameters array
, fn
, and flat
, flattening the array
to the specified depth, and then using the reduce()
method to iterate over each element of the flattened array
and apply the fn
function to it. The result of each application of fn
function is concatenated to the accumulating x
array, which is then returned by the reduce()
method. The map()
function returns the result of the reduce()
method. If any of the input parameters fail the validation checks, the function returns an empty array []
.
Next, let’s create afind
function. Here is an implementation of ourfind
function:Â
/**
* @name find
* @function
*
* @param {Array} array The input array
* @param {Function} fn The predicate function
* @param {Number} flat The input array flattening depth
*
* @description Finds the first array element for which the predicate is true
*
* @return {Array} The resulting array element
*
*/
const find = (array = [], fn = () => false, flat = 0) => inputsValid(array,fn,flat) ? array.flat(flat).reduce((x, y) => (x === undefined && fn(y) ? y : x), undefined): undefined;
The
find
function takes three parameters:array
,fn
, andflat
.It checks whether the input parameters
array
,fn
, andflat
are valid by calling theinputsValid
function. If any of the input parameters fail the validation checks, the function returnsundefined
.If all input parameters pass the validation checks, the function flattens the
array
to the specified depth using theflat()
method.It then uses the
reduce()
method to iterate over each element of the flattenedarray
.For each element of the flattened
array
, thefn
function is called with the current element as an argument.If an element passes the test implemented by the
fn
function, thereduce()
method returns that element, which is then returned by thefind()
function.If no element passes the test, the
reduce()
method returnsundefined
, which is then returned by thefind()
function.The
find()
function returnsundefined
if any of the input parameters fail the validation checks.
Ourfind
function searches the array
using the fn
function and returns the first element in array
that passes the test. It does this by validating the input parameters array
, fn
, and flat
, flattening the array
to the specified depth, and then using the reduce()
method to iterate over each element of the flattened array
and call the fn
function with the current element as an argument. If an element passes the test, that element is returned by the reduce()
method, which is then returned by the find()
function. If no element passes the test, the reduce()
method returns undefined
, which is then returned by the find()
function. If any of the input parameters fail the validation checks, the function returns undefined
.
Responses