Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/codewithreelofficial/functional-programming-javascript
https://github.com/codewithreelofficial/functional-programming-javascript
functional-programming javascript javascript-functions
Last synced: 1 day ago
JSON representation
- Host: GitHub
- URL: https://github.com/codewithreelofficial/functional-programming-javascript
- Owner: codewithreelofficial
- Created: 2018-07-25T01:49:20.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2018-08-22T04:12:47.000Z (over 6 years ago)
- Last Synced: 2024-12-13T23:34:33.537Z (about 2 months ago)
- Topics: functional-programming, javascript, javascript-functions
- Size: 86.9 KB
- Stars: 4
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Functional Programming Javascript
Functional programming is a way of writing clearner code through clever way of mutating, combinding, and using functions.
## Arrow Functions (Fat Arrows)
Arrow functions create a concise expression that encapsulates a small piece of functionality. Additionally, arrows retain the scope of the caller inside the function eliminating the need of `self = this`.
For example:
```javascript
// const multiply = function(x, y) {
// return x * y;
// }// Can be rewritten as:
// const multiply = (x, y) => { return x * y };// Since the function is a single expression return and braces are not needed:
const multiply = (x, y) => x * y;
console.log(multiply(5,10)) // 50
```## Scope
* Global scope
* Local scope
* Function scope
* Block scope
* Function hoisting and scope
* Functions do not have access to each other's scope
* Nested scope**Global scope**
If a variable is declared outside all functions or curly braces `({})`, it is said to be defined in the global scope.
```javascript
const globalVariable = 'some value';
```## Closure
Clousure is the functions that have access to the parent scope, even when the parent function has closed.
For every closure there are 3 scopes:
* Local scope ( Own scope)
* Outer functions scope
* Global scope## Function Delegates
Function delegates encapsulate a method allowing functions to be composed or passed as data.
For example:
```javascript
const isZero = n => n === 0;
const a = [0, 1, 0, 3, 4, 0];
console.log(a.filter(isZero)); // [0, 0, 0]
```## Expressions Instead of Statements
Statements define an action and are executed for their side effect. Expressions produce a result without mutating state.
For example:
Statement
```javascript
const getSalutation = function(hour) {
var salutation; // temp value
if (hour < 12) {
salutation = "Good Morning";
} else {
salutation = "Good Afternoon"
}
return salutation; // mutated value
}console.log(getSalutation(10)); // Good Morning
```Expression
```javascript
const getSalutation = (hour) => hour < 12 ? "Good Morning" : "Good Afternoon";
console.log(getSalutation(10)); // Good Morning
```## Higher Order Functions
A function that accepts another function as a parameter, or returns another function.
For example:
```javascript
function mapConsecutive(values, fn) {
let result = [];
for(let i=0; i < values.length -1; i++) {
result.push(fn(values[i], values[i+1]));
}
return result;
}const letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
let twoByTwo = mapConsecutive(letters, (x, y) => [x, y]);
console.log(twoByTwo); // [[a, b], [b, c], [c, d], [d, e], [e, f], [f, g]]
```## Pure Functions
A function that given the same input, will always return the same output. A pure function produces no side effects.
Note: Side effects may include:
* changing the file system
* inserting a record into a database
* making an http call
* mutations
* printing to the screen / logging
* obtaining user input
* querying the DOM
* accessing system stateFor example:
```javascript
var xs = [1, 2, 3, 4, 5];// ==== pure ====
xs.slice(0, 3);
//=> [1, 2, 3]xs.slice(0, 3);
//=> [1, 2, 3]xs.slice(0, 3);
//=> [1, 2, 3]// ==== pure ====
xs.splice(0, 3);
//=> [1, 2, 3]xs.splice(0, 3);
//=> [4, 5]xs.splice(0, 3);
//=> []// pure
var checkAge = function(age) {
var minimum = 21;
return age >= minimum;
};// impure
var minimum = 21;var checkAge = function(age) {
return age >= minimum;
};
```## Recursion
Recursion is the ability to call a function from within itself.
For example:
```javascript
function countUp(n) {
console.log(n);
if(n < 10) countUp(n+1);
}countUp(1);
```## Anonymous Functions
Anonymous function is the function that was declared without any named identifier to refer to it.
For example:
```javascript
// Normal function
function sayHi() {
alert('Hello world!');
}
sayHi();// Anonymous function assigned to sayHi variable
var sayHi = function() {
alert('Hello World!');
}// Use as an argument to other functions
setTimeout(function() {
console.log('Hello World!');
}, 1000);// Use as a closure
(function() {
alert('Hello World!');
})();// Use as a closure with parameters
(function(msg) {
alert(msg);
}('Hello World!'));// An anonymous function can refer to itself via arguments.callee local variable, useful for recursive anonymous functions
console.log(
(function(n) {
return (1 < n) ? arguments.callee(n - 1) + n : 1;
})(10)
);// Instead of using arguments.callee, you can use named function expression instead
console.log(
(function sum(n) {
return (n <= 1) ? 1 : sum(n-1) + n
})(10)
);
```## Currying
Currying allows a function with multiple arguments to be translated into a sequence of functions. Curried functions can be tailored to match the signature of another function.
```javascript
// Statement
// function convertUnits(toUnit = 0, factor, offset) {
// return function(input) {
// return ((offset + input) * factor).toFixed(2).concat(toUnit)
// }
// }// Can be written as an expression
const convertUnits = (toUnit, factor, offset = 0) => input => ((offset + input) * factor).toFixed(2).concat(toUnit);const milesToKm = convertUnits('km', 1.60936, 0);
const poundsToKg = convertUnits('kg', 0.45460, 0);
const farenheitToCelsius = convertUnits('degrees C', 0.5556, -32);console.log(milesToKm(10)); //"16.09 km"
console.log(poundsToKg(2.5)); //"1.14 kg"
console.log(farenheitToCelsius(98)); //"36.67 degrees C"const weightsInPounds = [5, 15.4, 9.8, 110];
// Without currying
// const weightsInKg = weightsInPounds.map(x => convertUnits('kg', 0.45460, 0)(x));// With currying
const weightsInKg = weightsInPounds.map(poundsToKg);
console.log(weightsInKg); // 2.27kg, 7.00kg, 4.46kg, 50.01kg
```## Array Manipulation Functions
Array Functions are the gateway to functional programming in JavaScript. These functions make short work of most imperative programming routines that work on arrays and collections.
***[].every(fn)***
Checks if all elements in an array pass a test.
***[].some(fn) | [].includes(fn)***
Checks if any of the elements in an array pass a test.
***[].find(fn)***
Returns the value of the first element in the array that passes a test.
***[].filter(fn)***
Creates an array filled with only the array elements that pass a test.
***[].map(fn)***
Creates a new array with the results of a function applied to every element in the array.
***[].reduce(fn(accumulator, currentValue))***
Executes a provided function for each value of the array (from left-to-right). Returns a single value, the accumulator.
***[].sort(fn(a,b))*** warning, mutates state!
Modifies an array by sorting the items within an array. An optional compare function can be used to customize sort behavior. Use the spread operator to avoid mutation. [...arr].sort()
***[].reverse()*** warning, mutates state!
Reverses the order of the elements in an array. Use the spread operator to avoid mutation. [...arr] . reverse()
For example:
```javascript
const names = [
{text: "Alpha", value: 5},
{text: "Beta", value: 2},
{text: "Gamma", value: 4},
];//Checks if all elements in an array pass a test.
let everyResult = names.every(x => x.value > 0); //true// Checks if any of the elements in an array pass a test.
let someResult = names.some(x => x.text === "Alpha"); //true// Returns the value of the first element in the array that passes a test.
let findResult = names.find(x => x.text === "Gamma"); //{text: "Gamma", value: 4}// Creates an array filled with only the array elements that pass a test.
let filterResult = names.filter(x => x.value > 3); //[{text: "Alpha", value: 5}, {text: "Gamma", value: 4}]// Creates a new array with the results of a function applied to every element in the array.
let mapResult = names.map(x => ({...x, value: x.value *10}));
//[{text: "Alpha", value: 50}, {text: "Beta", value: 20}, {text: "Gamma", value: 40}];// Executes a provided function for each value of the array (from left-to-right). The returns a single value, the accumulator.
let reduceResult = names.reduce((accumulator, currentValue) => currentValue.value > accumulator.value ? currentValue : accumulator);
// Get the largest object by value: {"text":"Alpha","value":5}// Modifies an array by sorting the items within an array. An optional compare function can be used to customize sort behavior. Use the spread operator to avoid mutation. [...arr].sort()
let sortResult = [...names].sort((a,b) => b.value - a.value);// reverses the order of the elements in an array. Use the spread operator to avoid mutation. [...arr].reverse()
let reverseResult = [...names].reverse();// Results
const appDiv = document.getElementById('app');
appDiv.innerHTML = `every: ${everyResult}
some: ${someResult}
find: ${JSON.stringify(findResult)}
filter: ${JSON.stringify(filterResult)}
map: ${JSON.stringify(mapResult)}
reduce: ${JSON.stringify(reduceResult)}
reverse: ${JSON.stringify(reverseResult)}
sort: ${JSON.stringify(sortResult)}
`;
```## Method Chaining
Method chains allow a series of functions to operate in succession to reach a final result. Method chains allow function composition similar to a pipeline.
For example:
```javascript
let cart = [
{ name: "Drink", price: 3.12 },
{ name: "Steak", price: 45.15},
{ name: "Drink", price: 11.01}
];let drinkTotal = cart.filter(x=> x.name === "Drink")
.map(x=> x.price)
.reduce((t,v) => t + v)
.toFixed(2);console.log(`Total Drink Cost $${drinkTotal}`); // Total Drink Cost $14.13
```## Pipelines
A pipeline allows for easy function composition when performing multiple operations on a variable. Since JavaScript lacks a Pipeline operator, a design pattern can be used to accomplish the task.
```javascript
const pipe = functions => data => {
return functions.reduce(
(value, func) => func(value),
data
);
};let cart = [3.12, 45.15, 11.01];
const addSalesTax = (total, taxRate) => (total * taxRate) + total;const tally = orders => pipe([
x => x.reduce((total, val) => total + val), // sum the order
x => addSalesTax(x, 0.09),
x => `Order Total = ${x.toFixed(2)}` // convert to text
])(orders);console.log(tally(cart)); // Order Total = 64.62
```