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 theapplyOperationfunction 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 apromisifyfunction. 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
promisifyfunction takes a callback-style functionfnas its input parameter.It returns a new function that accepts any number of arguments
(...args).This new function creates a new Promise using the
Promiseconstructor. This Promise resolves with thedataobject if thefnfunction executes without error, or rejects with theerrorobject if thefnfunction encounters an error.The
fnfunction is called with the given arguments (...args) and an additional callback function that takes anerrorobject and thedataobject as its two arguments.If the
errorobject is truthy, the Promise is rejected with theerrorobject.If the
errorobject is falsy, the Promise is resolved with thedataobject.
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 ademethodizefunction. 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
demethodizefunction takes a method functionfnas 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 originalfnfunction, but with itsthisvalue bound to the object passed as the first argument. In this case,...argsrepresents the object that the methodfnfunction 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
demethodizeConstructfunction takes two parameters: theSourceconstructor function whose prototype methods need to be demethodized, and theDestinationobject where the demethodized functions will be added.It loops through all the prototype methods of the
Sourceconstructor function using afor..ofloop and theObject.getOwnPropertyNamesmethod.For each prototype method, it creates a new function using the
demethodizefunction, passing in the method as thefnparameter and an empty object{}as thethisArgparameter.It adds the new demethodized function to the
Destinationobject with the same method name.The
Destinationobject 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
findOptimumfunction takes a functionfnas its input parameter.It returns a new function that takes one parameter
array.If
arrayis an array, the new function calls thereduce()method onarray, passing in thefnfunction as the first argument. Thereduce()method applies thefnfunction 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
arrayis 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
callFirstOnlyNTimesfunction takes three parameters:f,g, andn.It initializes a variable
donetofalse.It returns a new function that takes any number of arguments (
...args).The returned function checks if
doneisfalse. Ifdoneisfalse, the returned function setsdonetotrueand checks the value ofn.If
nis not a whole number, the returned function callsfwith the given arguments (...args).If
nis a whole number, the returned function callsfwith the given arguments (...args)ntimes using aforloop.If
doneistrue, the returned function callsgwith the given arguments (...args).The
ffunction will be called only the firstntimes the returned function is called, after which thegfunction 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 ourcallOnlyNTimes 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
callOnlyNTimesfunction takes two parameters:fnandn.It initializes a variable
donetofalse.It returns a new function that takes any number of arguments (
...args).The returned function checks if
doneisfalse. Ifdoneisfalse, the returned function setsdonetotrueand callsfnntimes using aforloop.The
fnfunction will be called only the firstntimes 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 ourbillOnceAndOnlyOncefunction:Â
/**
* @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
billOnceAndOnlyOncefunction takes two parameters:billanddontBill.It initializes a variable
timeToBilltobill.It returns a new function that takes any number of arguments (
...args).The returned function calls
timeToBillwith the given arguments (...args) and stores the result in a variableresult.The returned function then sets
timeToBilltodontBill.Finally, the returned function returns the
result.The
billfunction will be called only the first time the returned function is called, and thedontBillfunction 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 inputsValidfunction. 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
inputsValidfunction takes three parameters:array,fn, andflat.It checks if
arrayis an array by using theArray.isArray()method. Ifarrayis not an array, the function returnsfalse.It checks if
fnis a function by using thetypeofoperator. Iffnis not a function, the function returnsfalse.It checks if
flatis a whole number orInfinityby using thetypeofoperator and the modulo operator (%). Ifflatis 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 ournone 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
nonefunction takes three parameters:array,fn, andflat.It checks whether the input parameters
array,fn, andflatare valid by calling theinputsValidfunction. 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
arrayto the specified depth using theflat()method.It then uses the
every()method to check whether none of the elements in the flattenedarraypass the test implemented by thefnfunction.If none of the elements pass the test, the function returns
true. Otherwise, it returnsfalse.
Ournonefunction 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
forEachAsyncfunction takes three parameters:array,fn, andflat.It checks whether the input parameters
array,fn, andflatare valid by calling theinputsValidfunction. 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
arrayto the specified depth using theflat()method.It then uses the
reduce()method to iterate over each element of the flattenedarrayasynchronously.For each element of the flattened
array, thefnfunction 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 ofarrayhave 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 mapAsyncfunction. Here is an implementation of ourmapAsyncfunction:Â
/**
* @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
mapAsyncfunction takes three parameters:array,fn, andflat.It checks whether the input parameters
array,fn, andflatare valid by calling theinputsValidfunction. 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
arrayto the specified depth using theflat()method.It then uses the
map()method to apply thefnfunction to each element of the flattenedarray.The
map()method returns an array of Promises, which resolve to the results of applying thefnfunction 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 thefnfunction 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
filterAsyncfunction takes three parameters:array,fn, andflat.It checks whether the input parameters
array,fn, andflatare valid by calling theinputsValidfunction. 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 thefnfunction to each element of the flattenedarray.The
mapAsync()function returns a Promise that resolves to an array of the results of applying thefnfunction 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 originalarrayis 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 reduceAsyncfunction. Here is an implementation of ourreduceAsyncfunction:Â
/**
* @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
reduceAsyncfunction takes four parameters:array,fn,init, andflat.It checks whether the input parameters
array,fn, andflatare valid by calling theinputsValidfunction. 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
arrayto the specified depth using theflat()method.It then uses the
forEachAsync()function to iterate over each element of the flattenedarrayasynchronously.For each element of the flattened
array, thefnfunction 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 ofarrayhave been processed by thefnfunction.
OurreduceAsyncfunction 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 afilteredfunction. Here is an implementation of ourfilteredfunction:Â
/**
* @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
filteredfunction takes three parameters:array,fn, andflat.It checks whether the input parameters
array,fn, andflatare valid by calling theinputsValidfunction. 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
arrayto the specified depth using theflat()method.It then uses the
filter()method to filter the flattenedarraybased on thefnfunction.The
filter()method returns a new array containing the elements ofarraythat pass the test implemented by thefnfunction.The
filtered()function returns the new filtered array.
Ourfilteredfunction 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
filterItemsfunction takes two parameters:queryandarray.It checks whether the input parameter
arrayis an array by calling theArray.isArray()method. Ifarrayis not an array, the function returns an empty array[].If
arrayis an array, the function uses thefilter()method to create a new array containing the elements ofarraythat contain thequerystring.The
filter()method iterates over each element ofarrayand calls a callback function for each element. The callback function tests whether the element contains thequerystring using theindexOf()method. If thequerystring 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 ofarraythat contain thequerystring.
OurfilterItemsfunction 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 asomefunction. Here is an implementation of oursomefunction:Â
/**
* @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
somefunction takes three parameters:array,fn, andflat.It checks whether the input parameters
array,fn, andflatare valid by calling theinputsValidfunction. 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
arrayto the specified depth using theflat()method.It then uses the
reduce()method to iterate over each element of the flattenedarrayand test it using thefnfunction.For each element of the flattened
array, thefnfunction is called to test whether the element passes the test.If at least one element in the
arraypasses the test implemented by thefnfunction, thereduce()method returnstrue. Otherwise, it returnsfalse.The
some()function returns the boolean value returned by thereduce()method.
Oursomefunction tests thearrayusing 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 aeveryfunction. Here is an implementation of oureveryfunction:Â
/**
* @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
everyfunction takes four parameters:array,fn,flat, andresult.It checks whether the input parameters
array,fn, andflatare valid by calling theinputsValidfunction. 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
arrayto the specified depth using theflat()method.It then uses the
reduce()method to iterate over each element of the flattenedarrayand test it using thefnfunction.For each element of the flattened
array, thefnfunction is called to test whether the element passes the test.If an element passes the test, it is added to the
resultarray using thepush()method.If an element does not pass the test, it is removed from the
resultarray using thepop()method.If all elements in the
arraypass the test implemented by thefnfunction, theresultarray will be equal to the flattenedarray, and the function returnstrue. Otherwise, it returnsfalse.The
every()function returns the boolean value returned by thereduce()method.
Oureveryfunction 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 aforEachfunction. Here is an implementation of ourforEachfunction:Â
/**
* @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
forEachfunction takes three parameters:array,fn, andflat.It checks whether the input parameters
array,fn, andflatare valid by calling theinputsValidfunction. 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
arrayto the specified depth using theflat()method.It then uses a
forloop to iterate over each element of the flattenedarray.For each element of the flattened
array, thefnfunction is called with the current element as its argument.The function does not return a value.
OurforEachfunction 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 afilterfunction. Here is an implementation of ourfilterfunction:Â
/**
* @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
filterfunction takes four parameters:array,fn,flat, andresult.It checks whether the input parameters
array,fn, andflatare valid by calling theinputsValidfunction. 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
arrayto the specified depth using theflat()method.It then uses a
forloop to iterate over each element of the flattenedarray.For each element of the flattened
array, thefnfunction is called with the current element, index and the entirearrayas arguments, to test whether the element passes the test.If an element passes the test implemented by the
fnfunction, it is added to theresultarray using thepush()method.If an element does not pass the test, it is not added to the
resultarray.The
filter()function returns theresultarray if it contains any elements that passed the test. Otherwise, it returns an empty array[].
Ourfilterfunction 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 flattenfunction. Here is an implementation of ourflattenfunction:Â
/**
* @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
flattenfunction takes two parameters:arrayandresult.The function first checks whether the input parameter
arrayis an array using theArray.isArray()method. Ifarrayis not an array, it returns theresultarray.If
arrayis an array, the function uses theforEach()method to iterate over each element ofarray.For each element of
array, theflattenfunction checks whether it is an array using theArray.isArray()method.If the element is an array, the
flattenfunction calls itself recursively, passing the element as thearrayparameter and theresultarray as theresultparameter.If the element is not an array, the
flattenfunction adds it to theresultarray using thepush()method.The
flatten()function returns theresultarray after all elements ofarrayhave been flattened.
Ourflattenfunction 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 afindIndexfunction. Here is an implementation of ourfindIndexfunction:Â
/**
* @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
findIndexfunction takes three parameters:array,fn, andflat.It checks whether the input parameters
array,fn, andflatare valid by calling theinputsValidfunction. 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
arrayto 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, thefnfunction is called with the current element, index and the entirearrayas arguments, to test whether the element passes the test.If an element passes the test implemented by the
fnfunction, 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 returnsundefinedif 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 mapfunction. Here is an implementation of ourmapfunction:Â
/**
* @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
mapfunction takes three parameters:array,fn, andflat.It checks whether the input parameters
array,fn, andflatare valid by calling theinputsValidfunction. 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
arrayto 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, thefnfunction is called with the current element as an argument, and the result is concatenated to the accumulatingxarray.The
reduce()method returns the accumulatedxarray after all elements of the flattenedarrayhave 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 afindfunction. Here is an implementation of ourfindfunction:Â
/**
* @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
findfunction takes three parameters:array,fn, andflat.It checks whether the input parameters
array,fn, andflatare valid by calling theinputsValidfunction. 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
arrayto 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, thefnfunction is called with the current element as an argument.If an element passes the test implemented by the
fnfunction, 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 returnsundefinedif any of the input parameters fail the validation checks.
Ourfindfunction 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.
and then
Responses