We have one left...
These methods iterate over the array
Calls a function you provide for each element in the Array
function logTheThings(element, index, array){
console.log('Current element is: ', element);
}
var myArray = [3, 'taco', false, 'Wonka'];
myArray.forEach(logTheThings);
//Current element is: 3
//Current element is: 'taco'
//Current element is: false
//Current element is: 'Wonka'
Your callback function takes 3 params:
var myArray = [3, 'taco', false, 'Wonka'];
myArray.forEach(function(element, index, array) {
console.log('Current element is: ', element);
});
//Current element is: 3
//Current element is: 'taco'
//Current element is: false
//Current element is: 'Wonka'
=>
TIP: If you don't want the function to run against an element return false
Returns true if every element in the Array passes the test you provide
Your callback function takes 3 params:
function isNumeric(element, index, array) {
return !isNaN(parseInt(element));
}
var myArray = [3, 'taco', false, 'Wonka'];
myArray.every(isNumeric); //return false
var myOtherArray = [3, 5, 6, 9];
myArray.every(isNumeric); //return true
Returns true if ANY element in the Array passes the test you provide
Your callback function takes 3 params:
function hazNumber(element, index, array) {
return !isNaN(parseInt(element));
}
var myArray = [3, 'taco', false, 'Wonka'];
myArray.some(hazNumber); //return true, 1 iteration
var myOtherArray = ['test', 'taco', 'hotdog', {}];
myOtherArray.some(hazNumber); //return false, 4 iterations
Returns immediately when first true is found
Creates and returns a new array with all elements that pass true test
Your callback function takes 3 params:
function getNumberz(element, index, array) {
return !isNaN(parseInt(element));
}
var myArray = [3, 'taco', false, 44, 'Wonka'];
myArray.filter(getNumberz); //return [3, 44]
console.log(myArray); //[3, 'taco', false, 44, 'Wonka']
var myOtherArray = ['test', 'taco', 'hotdog', {}];
myOtherArray.filter(getNumberz); //return []
console.log(myOtherArray); //['test', 'taco', 'hotdog', {}]
NOTE: filter() does NOT mutate the original array
Creates/returns a new array with all returned values from callback function
Your callback function takes 3 params:
function tripleIt(element, index, array) {
return element * 3;
}
var myArray = [3, 12, 1, 9];
myArray.map(tripleIt); //return [9, 36, 3, 27]
console.log(myArray) //[3, 12, 1, 9]
var myOtherArray = [3, 12, 1, 'taco'];
myOtherArray.map(tripleIt); //return [9, 36, 3, NaN]
console.log(myArray) //[3, 12, 1, 'taco']
NOTE: map() does NOT mutate the original array
Returns a single value accumulated against all values from callback function
Your callback function takes 4 params and 1 optional param:
function summarize(previousValue, currentValue, index, array) {
return previousValue + currentValue;
}
var myArray = [3, 12, 1, 9];
myArray.reduce(summarize); //return 25
console.log(myArray) //[3, 12, 1, 9]
//Start at a certain initial value
myArray.reduce(summarize, 10); //return 35
console.log(myArray) //[3, 12, 1, 9]
NOTE: reduce() does NOT mutate the original array
If you pass NO optional param, first iteration is at index 1 so that previous/next have values
//Omit index and array is still valid
function summarize(previousValue, currentValue) {
return previousValue + currentValue;
}
var myArray = [3, 12, 1, 9];
myArray.reduce(summarize); //return 25
console.log(myArray) //[3, 12, 1, 9]
//Start at a certain initial value
myArray.reduce(summarize, 10); //return 35
console.log(myArray) //[3, 12, 1, 9]
Returns a single value accumulated against all values from callback function
Your callback function takes 4 params and 1 optional param:
NOTE: reduceRight() does NOT mutate the original array
reduceRight() has the same functionality as reduce() except that it starts from the right side of the input array
How does it work?
Defines computation as statements that change a program state.
What does it do?
Express the desired result by describing rules, constraints, and relationships-- without explicitly mutating state.
Before computers were invented, mathematicians invented two
Universal Models of Computation
(1) Turing Machines
(state visualized as a ticker tape of infinite length)
(2) Lambda Calculus
(no state, just functions)
Turing eventually proved both Universal Models of Computation are mathematically equivalent - both can express any computable algorithm
As it turned out, Turing Machines very closely matched the actual hardware of computers. Instead of infinite ticker tape, real computers have finite memory, but everything else is the same.
Imperative programming became by far the dominant paradigm.
Lambda calculus was majorly sidelined for decades... until...
brought functional programming to the masses
JS was the first popular programming language combining the power of "higher order functions" with C-like syntax most programmers are familiar with.
"Higher order functions" means functions can take functions as parameters and can return functions as output.
const greaterThan = a => b => b > a
// use it like this:
const greaterThan10 = greaterThan(10)
console.log(greaterThan10(11)) // true
const maybeDouble = (predicate, n) =>
predicate(n) ? n * 2 : n
// use it like this:
const isOdd = n => n % 2 === 1
console.log(maybeDouble(isOdd, 5)) // 10
btw, "predicate" is just a fancy word for a function that returns only true or false. There are lots of fancy words in functional programming for things that are actually quite simple. Don't be intimidated.
Suppose we have two functions:
const addTwo = n => n + 2
const multiplyByFour = n => 4 * n
Note that there are two ways to compose them:
const multiplyByFourThenAddTwo =
x => addTwo(multiplyByFour(x))
const addTwoThenMultiplyByFour =
x => multiplyByFour(addTwo(x))
Text
Text
The cornerstone of functional programming is...
Problem
Manually invoking functions in series is tedious, error-prone, and difficult for code re-use.
Consider:
func1(func2(func3(func4(func5(func6(func7(x)))))))
Can we do better?
const a = func7(x)
const b = func6(a)
const c = func5(b)
const d = func4(c)
const e = func3(d)
const f = func2(e)
const g = func1(f)
Or:
const funcs = [addTwo, multipleByFour]
Imagine an array of functions...
How can we compose them in the general case?
const compose = (...funcs) => input =>
funcs.reduceRight((prevOutput, nextFunc) =>
nextFunc(prevOutput), input)
const pipe = (...funcs) => input =>
funcs.reduce((prevOutput, nextFunc) =>
nextFunc(prevOutput), input)
compose(...funcs)(4) // 18, right-to-left
pipe( ...funcs)(4) // 24, left-to-right
// imagine beging able to rewrite this:
const myNumber = Math.round(Math.sqrt(Math.PI))
// as this:
const myNumber = Math.PI |> Math.sqrt |> Math.round
// other symbols considered for the pipeline operator:
// :: -> ~> ..
Sidenote: did you know future javascript might have a pipeline operator?
Test it out here
Although some mathematicians prefer compose
(it's sort of like reverse polish notation),
pipe is like English
(and many other languages):
data flows left-to-right, top-to-bottom.
Notice something about the functions you pass to compose and pipe?
They all have exactly one parameter.
In functional programming, we say they all have an arity of one (unary).
Arity is just a fancy word for the number of parameters a function has.
In pure functional programming
(lambda calculus), all functions have an arity of exactly one.
The next concept you are likely to run into in functional programming is
Named after Haskell Curry, mathematician
Currying is the process of converting a function, that accepts n arguments, into a sequence of n chained function calls, having exactly one argument each.
// uncurried
const multiply = (a, b) => a * b
multiply(2, 3) // 6
// curried
const curriedMultiply = a => b => a * b
curriedMultiply(2)(3) // 6
Glad you asked...
const curry = (f, arr = []) => (...args) => (
a => a.length === f.length
? f(...a)
: curry(f, a)
)([...arr, ...args])
// currying gives us SUPERPOWERS, like this:
const multiply = (a, b) => a * b
const multiplyBy4 = curry(multiply)(4)
multiplyBy4(3) // 12
// now we can convert any multi-arity function
// into a Function Factory :)
// remember this?
// const funcs = [addTwo, multipleByFour]
// now we can refactor it like this:
const add = (a, b) => a + b
const multiply = (a, b) => a * b
const addTo = curry(add)
const multiplyBy = curry(multiply)
const funcs = [addTo(2), multiplyBy(4)]
pipe(...funcs)(4) // 24
Lodash is by far the most popular library, but lodash/fp is comparatively little-known. lodash/fp functions are wrappers around the better known non-fp lodash functions, so if you are already using lodash, lodash/fp is probably your best choice.
Ramda is a little more hardcore functional than lodash/fp because most of the functions assume currying. If you are a functional geek, you might enjoy ramda over lodash/fp.
Rambda bills itself as smaller and faster than ramda, but it is probably the most obscure choice, and has the fewest utility functions.