# 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 **the applyOperationfunction** 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 a`promisify`

function. Here is an implementation of our`promisify`

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 function`fn`

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 the`data`

object if the`fn`

function executes without error, or rejects with the`error`

object if the`fn`

function encounters an error.The

`fn`

function is called with the given arguments (`...args`

) and an additional callback function that takes an`error`

object and the`data`

object as its two arguments.If the

`error`

object is truthy, the Promise is rejected with the`error`

object.If the

`error`

object is falsy, the Promise is resolved with the`data`

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 a`demethodize`

function. Here is an implementation of our`demthodize`

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 function`fn`

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)`

. The`bind()`

method creates a new function with the same body as the original`fn`

function, but with its`this`

value bound to the object passed as the first argument. In this case,`...args`

represents the object that the method`fn`

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 our`promisify`

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: the`Source`

constructor function whose prototype methods need to be demethodized, and the`Destination`

object where the demethodized functions will be added.It loops through all the prototype methods of the

`Source`

constructor function using a`for..of`

loop and the`Object.getOwnPropertyNames`

method.For each prototype method, it creates a new function using the

`demethodize`

function, passing in the method as the`fn`

parameter and an empty object`{}`

as the`thisArg`

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 a`findOptimum`

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 function`fn`

as its input parameter.It returns a new function that takes one parameter

`array`

.If

`array`

is an array, the new function calls the`reduce()`

method on`array`

, passing in the`fn`

function as the first argument. The`reduce()`

method applies the`fn`

function to each element of the array and returns a single value that represents the optimum value. The`reduce()`

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 returns`null`

.

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`

, and`n`

.It initializes a variable

`done`

to`false`

.It returns a new function that takes any number of arguments (

`...args`

).The returned function checks if

`done`

is`false`

. If`done`

is`false`

, the returned function sets`done`

to`true`

and checks the value of`n`

.If

`n`

is not a whole number, the returned function calls`f`

with the given arguments (`...args`

).If

`n`

is a whole number, the returned function calls`f`

with the given arguments (`...args`

)`n`

times using a`for`

loop.If

`done`

is`true`

, the returned function calls`g`

with the given arguments (`...args`

).The

`f`

function will be called only the first`n`

times the returned function is called, after which the`g`

function will be called every time the returned function is called.

Our`callFirstOnlyNTimes`

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`

and`n`

.It initializes a variable

`done`

to`false`

.It returns a new function that takes any number of arguments (

`...args`

).The returned function checks if

`done`

is`false`

. If`done`

is`false`

, the returned function sets`done`

to`true`

and calls`fn`

`n`

times using a`for`

loop.The

`fn`

function will be called only the first`n`

times the returned function is called.

Our`callOnlyNTimes`

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 our`billOnceAndOnlyOnce`

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`

and`dontBill`

.It initializes a variable

`timeToBill`

to`bill`

.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 variable`result`

.The returned function then sets

`timeToBill`

to`dontBill`

.Finally, the returned function returns the

`result`

.The

`bill`

function will be called only the first time the returned function is called, and the`dontBill`

function will be called every time after that.

Our`billOnceAndOnlyOnce`

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 our`inputsValid`

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`

, and`flat`

.It checks if

`array`

is an array by using the`Array.isArray()`

method. If`array`

is not an array, the function returns`false`

.It checks if

`fn`

is a function by using the`typeof`

operator. If`fn`

is not a function, the function returns`false`

.It checks if

`flat`

is a whole number or`Infinity`

by using the`typeof`

operator and the modulo operator (`%`

). If`flat`

is not a whole number or`Infinity`

, the function returns`false`

.If all three input parameters pass the validation checks, the function returns

`true`

. Otherwise, it returns`false`

.

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`

, and`flat`

.It checks whether the input parameters

`array`

,`fn`

, and`flat`

are valid by calling the`inputsValid`

function. If any of the input parameters fail the validation checks, the function returns`false`

.If all input parameters pass the validation checks, the function flattens the

`array`

to the specified depth using the`flat()`

method.It then uses 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`

.

Our`none`

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 our`forEachAsync`

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`

, and`flat`

.It checks whether the input parameters

`array`

,`fn`

, and`flat`

are valid by calling the`inputsValid`

function. If any of the input parameters fail the validation checks, the function returns`undefined`

.If all input parameters pass the validation checks, the function flattens the

`array`

to the specified depth using the`flat()`

method.It then uses the

`reduce()`

method to iterate over each element of the flattened`array`

asynchronously.For each element of the flattened

`array`

, the`fn`

function is called using`Promise.then()`

. This ensures that the elements are processed in the correct order.The

`reduce()`

method returns a Promise that resolves when all elements of`array`

have been processed.

Our`forEachAsync`

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 our`mapAsync`

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`

, and`flat`

.It checks whether the input parameters

`array`

,`fn`

, and`flat`

are valid by calling the`inputsValid`

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 the`flat()`

method.It then uses the

`map()`

method to apply the`fn`

function to each element of the flattened`array`

.The

`map()`

method returns an array of Promises, which resolve to the results of applying the`fn`

function to each element of`array`

.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 the`fn`

function to each element of`array`

.

Our`mapAsync`

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 our`filterAsync`

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`

, and`flat`

.It checks whether the input parameters

`array`

,`fn`

, and`flat`

are valid by calling the`inputsValid`

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 the`fn`

function to each element of the flattened`array`

.The

`mapAsync()`

function returns a Promise that resolves to an array of the results of applying the`fn`

function to each element of the flattened`array`

.The Promise returned by

`mapAsync()`

is then used to filter the original`array`

. If the Promise resolves to an array of values that are truthy, then the corresponding element in the original`array`

is included in the result array. Otherwise, the element is excluded.Finally, the Promise is resolved to the filtered array.

Our`filterAsync`

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 our`reduceAsync`

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`

, and`flat`

.It checks whether the input parameters

`array`

,`fn`

, and`flat`

are valid by calling the`inputsValid`

function. If any of the input parameters fail the validation checks, the function returns`0`

.`array`

to the specified depth using the`flat()`

method.It then uses the

`forEachAsync()`

function to iterate over each element of the flattened`array`

asynchronously.For each element of the flattened

`array`

, the`fn`

function is called using the`Promise.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 of`array`

have been processed by the`fn`

function.

Our`reduceAsync`

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 a`filtered`

function. Here is an implementation of our`filtered`

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`

, and`flat`

.It checks whether the input parameters

`array`

,`fn`

, and`flat`

are valid by calling the`inputsValid`

function. If any of the input parameters fail the validation checks, the function returns an empty array`[]`

.`array`

to the specified depth using the`flat()`

method.It then uses the

`filter()`

method to filter the flattened`array`

based on the`fn`

function.The

`filter()`

method returns a new array containing the elements of`array`

that pass the test implemented by the`fn`

function.The

`filtered()`

function returns the new filtered array.

Our`filtered`

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 our`filterItems`

` 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`

and`array`

.It checks whether the input parameter

`array`

is an array by calling the`Array.isArray()`

method. If`array`

is not an array, the function returns an empty array`[]`

.If

`array`

is an array, the function uses the`filter()`

method to create a new array containing the elements of`array`

that contain the`query`

string.The

`filter()`

method iterates over each element of`array`

and calls a callback function for each element. The callback function tests whether the element contains the`query`

string using the`indexOf()`

method. If the`query`

string is found in the element, the callback function returns`true`

, which includes the element in the new array. Otherwise, the callback function returns`false`

, which excludes the element from the new array.The

`filterItems()`

function returns the new array containing the elements of`array`

that contain the`query`

string.

Our`filterItems`

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 a`some`

function. Here is an implementation of our`some`

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`

, and`flat`

.It checks whether the input parameters

`array`

,`fn`

, and`flat`

are valid by calling the`inputsValid`

function. If any of the input parameters fail the validation checks, the function returns`false`

.`array`

to the specified depth using the`flat()`

method.It then uses the

`reduce()`

method to iterate over each element of the flattened`array`

and test it using the`fn`

function.For each element of the flattened

`array`

, the`fn`

function is called to test whether the element passes the test.If at least one element in the

`array`

passes the test implemented by the`fn`

function, the`reduce()`

method returns`true`

. Otherwise, it returns`false`

.The

`some()`

function returns the boolean value returned by the`reduce()`

method.

Our`some`

function tests the`array`

using the`fn`

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 a`every`

function. Here is an implementation of our`every`

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`

, and`result`

.It checks whether the input parameters

`array`

,`fn`

, and`flat`

are valid by calling the`inputsValid`

function. If any of the input parameters fail the validation checks, the function returns`false`

.`array`

to the specified depth using the`flat()`

method.It then uses the

`reduce()`

method to iterate over each element of the flattened`array`

and test it using the`fn`

function.For each element of the flattened

`array`

, the`fn`

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 the`push()`

method.If an element does not pass the test, it is removed from the

`result`

array using the`pop()`

method.If all elements in the

`array`

pass the test implemented by the`fn`

function, the`result`

array will be equal to the flattened`array`

, and the function returns`true`

. Otherwise, it returns`false`

.The

`every()`

function returns the boolean value returned by the`reduce()`

method.

Our`every`

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 a`forEach`

function. Here is an implementation of our`forEach`

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`

, and`flat`

.It checks whether the input parameters

`array`

,`fn`

, and`flat`

are valid by calling the`inputsValid`

function. If any of the input parameters fail the validation checks, the function returns`undefined`

.`array`

to the specified depth using the`flat()`

method.It then uses a

`for`

loop to iterate over each element of the flattened`array`

.For each element of the flattened

`array`

, the`fn`

function is called with the current element as its argument.The function does not return a value.

Our`forEach`

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 a`filter`

function. Here is an implementation of our`filter`

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`

, and`result`

.`array`

,`fn`

, and`flat`

are valid by calling the`inputsValid`

function. If any of the input parameters fail the validation checks, the function returns an empty array`[]`

.`array`

to the specified depth using the`flat()`

method.It then uses a

`for`

loop to iterate over each element of the flattened`array`

.For each element of the flattened

`array`

, the`fn`

function is called with the current element, index and the entire`array`

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 the`result`

array using the`push()`

method.If an element does not pass the test, it is not added to the

`result`

array.The

`filter()`

function returns the`result`

array if it contains any elements that passed the test. Otherwise, it returns an empty array`[]`

.

Our`filter`

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 our`flatten`

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`

and`result`

.The function first checks whether the input parameter

`array`

is an array using the`Array.isArray()`

method. If`array`

is not an array, it returns the`result`

array.If

`array`

is an array, the function uses the`forEach()`

method to iterate over each element of`array`

.For each element of

`array`

, the`flatten`

function checks whether it is an array using the`Array.isArray()`

method.If the element is an array, the

`flatten`

function calls itself recursively, passing the element as the`array`

parameter and the`result`

array as the`result`

parameter.If the element is not an array, the

`flatten`

function adds it to the`result`

array using the`push()`

method.The

`flatten()`

function returns the`result`

array after all elements of`array`

have been flattened.

Our`flatten`

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 a`findIndex`

function. Here is an implementation of our`findIndex`

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`

, and`flat`

.It checks whether the input parameters

`array`

,`fn`

, and`flat`

are valid by calling the`inputsValid`

function. If any of the input parameters fail the validation checks, the function returns`undefined`

.`array`

to the specified depth using the`flat()`

method.It then uses the

`reduce()`

method to iterate over each element of the flattened`array`

.For each element of the flattened

`array`

, the`fn`

function is called with the current element, index and the entire`array`

as arguments, to test whether the element passes the test.If an element passes the test implemented by the

`fn`

function, the`reduce()`

method returns the index of that element, 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.The

`findIndex()`

function returns`undefined`

if any of the input parameters fail the validation checks.

Our`findIndex`

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 our`map`

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`

, and`flat`

.`array`

,`fn`

, and`flat`

are valid by calling the`inputsValid`

function. If any of the input parameters fail the validation checks, the function returns an empty array`[]`

.`array`

to the specified depth using the`flat()`

method.It then uses the

`reduce()`

method to iterate over each element of the flattened`array`

.For each element of the flattened

`array`

, the`fn`

function is called with the current element as an argument, and the result is concatenated to the accumulating`x`

array.The

`reduce()`

method returns the accumulated`x`

array after all elements of the flattened`array`

have been mapped.The

`map()`

function returns the result of the`reduce()`

method.The

`map()`

function returns an empty array`[]`

if any of the input parameters fail the validation checks.

Our`map`

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 a`find`

function. Here is an implementation of our`find`

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`

, and`flat`

.`array`

,`fn`

, and`flat`

are valid by calling the`inputsValid`

function. If any of the input parameters fail the validation checks, the function returns`undefined`

.`array`

to the specified depth using the`flat()`

method.It then uses the

`reduce()`

method to iterate over each element of the flattened`array`

.For each element of the flattened

`array`

, the`fn`

function is called with the current element as an argument.If an element passes the test implemented by the

`fn`

function, the`reduce()`

method returns that element, 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.The

`find()`

function returns`undefined`

if any of the input parameters fail the validation checks.

Our`find`

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