Use of declarative functions (as opposed to imperative)
Proper use of caching (computing efficiency)
Pure functions
Composing (chained atomic pure operations)
Pure functions
Don't mutate state (global scope)
Always have a return statement. This is useful for chaining purposes
Idempotence. On the same input, return the same output, regardless of how many times executed
Usually have 1 argument
//Side effects:
const array = [1,2,3];
function mutateArray(arr) {
arr.pop()
}
function mutateArray2(arr) {
arr.forEach(item => arr.push(1
))
}
//The order of the function calls will matter.
mutateArray(array)
mutateArray2(array)
array
// Idempotence:
function notGood() {
return Math.random()
// new Date();
}
function good() { //pure function
return 5
}
Math.abs(Math.abs(10)) //pure function
Cache in memory
//Memoization
//learn to cache
function addTo80(n) {
return n + 80;
}
addTo80(5)
let cache = {};
function memoizeAddTo80(n) {
if (n in cache) {
console.log('quickly rerieved from cache');
return cache[n];
} else {
console.log('expensive operation');
const answer = n + 80;
cache[n] = answer;
return answer;
}
}
Here is a better implementation of caching, making the above pure.
// let's make that better with no global scope.
function memoizeAddTo80(n) {
let cache = {};
return function(n) { //This is closure in javascript.
if (n in cache) {
console.log('quickly rerieved from cache');
return cache[n];
} else {
console.log('expensive operation');
const answer = n + 80;
cache[n] = answer;
return answer;
}
}
}
const memoized = memoizeAddTo80();
console.log(1, memoized(6))
// console.log(cache)
// console.log('-----------')
console.log(2, memoized(6))
Currying and Composing
Currying in JavaScript transforms a function that takes multiple arguments into a sequence of functions, each taking a single argument. For example, a function f(a, b) becomes f(a)(b). It allows partial application of functions, where you can fix some arguments and pass others later, enabling more flexible function usage.
// add two numbers
const add = a => b => a + b;
//similar to
const add2 = a => {
return b => {
return (a + b)
}
}
const result = add(2)(3); // => 5
pipe() and compose()
Composing is the process of chaining functions. In other words, through pipe() and compose() we create a pipeline of functions with the output of one function connected to the input of the next. This is the reason for which these functions need to be pure.
//as seen on freecodecamp.org/news/pipe-and-compose-in-javascript-5b04004ac937/
//Let’s write a function that returns someone’s name.
getName = (person) => person.name;
getName({ name: 'Buckethead' });
// 'Buckethead'
//Let’s write a function that uppercases strings.
uppercase = (string) => string.toUpperCase();
uppercase('Buckethead');
// 'BUCKETHEAD'
//What if we want to add a function that gets the first 6 characters of a string?
get6Characters = (string) => string.substring(0, 6);
get6Characters('Buckethead');
// 'Bucket'
//Let’s get really crazy and add a function to reverse strings.
reverse = (string) =>
string
.split('')
.reverse()
.join('');
reverse('Buckethead');
// 'daehtekcuB'
//chaining all the operations would result in
reverse(get6Characters(uppercase(getName({ name: 'Buckethead' }))));
// 'TEKCUB
Instead of jamming functions within functions or creating a bunch of intermediate variables, let’s pipe all the things!