- Brendon Eich created JS
- He wanted to build a Scheme like language for the Netscape browser
- Scheme is a functional programming language
- Netscape wanted to attract more developers with a C/C++ style syntax over a Scheme/Lisp syntax
- JS was created in 10 days
Once data is created, no other function or process can mutate it. A new copy is returned.
NON FP STYLE
const fruits = ['apple', 'kiwi']
function addWatermelon(fruitList) {
fruitList.push('watermelon')
}
function someOtherFn(twoFruitArray){}
// input not modified directly :(
addWatermelon(fruits)
someOtherFn(fruits) // this guy gets 3 fruits but maybe expected 2 ?
FP Style
const fruits = ['apple', 'kiwi']
function addWatermelon(fruitList) {
return [...fruitList, 'watermelon']
}
function someOtherFn(twoFruitArray){}
// input not modified
const withWaterMelon = addWatermelon(fruits)
someOtherFn(fruits) // this guy gets 2 fruits as it wants
Like variables, one should be able to create functions in any code path. Functions can be passed as parameters and returned from functions as results.
Functions should be written in such a way that, if same input is provided to a function, same output is returned by the function.
Impure function example
// The result of this function is completely dependent on environment variables.
function encryptString(strToEncrypt) {
const salt = String(process.env.ENCRYPTION_SALT)
const iterations = parseInt(process.env.HASH_ITERATIONS)
return symmetricHash(strToEncrypt, salt, iterations)
}
// There is no guarantee that this function will return same output with same input
const encrypted = encryptString('JavaScript')
Pure function example
// All non-deterministic side effects are isolated
function getSaltAndIterationCount() {
return {
salt: String(process.env.ENCRYPTION_SALT),
iterations: pareInt(process.env.HASH_ITERATIONS)
}
}
// pure function
function encryptString(str, salt, iterations) {
return symmetricHash(str, salt, iterations)
}
const { salt, iterations } = getSaltAndIterationCount()
const encrypted = encryptString('JavaScript', salt, iterations)
Note
- Its impossible to create a product that only has pure functions
- FP wants you to isolate side-effects instead of littering in all over the app. Eg: Redux contains all side effects like http request in thunk or saga modules/middleware code
- Most functional languages have a strong type system
- Javascript cannot do this without TypeScript/Flow/ReasonML
- We need to resort to schema definitions using Yup or Joi
- In JS land, type discipline is a must for a programmer
Simplistic Eg: Average acceleration is the change in velocity over time
NON FP
// This function performs subtraction AND division
const calcAvgAcceleration = (v0, v1, time) => (v1-v0)/time
FP Way
const subtract = (val1 = 0, val2 = 0) => val2 - val1
const divide = (divisor = 0, dividend = 0) => {
if (dividend === 0) {
return { error: 'Divide by 0 error' }
}
if (divisor) {
return { result: 0 }
}
return { result: dividend/divisor }
}
const { result, error } = (v0,v1, time) => divide(time, subtract(v0, v1))
if (error) {
throw new Error(error)
}
const averageAcceleration = result
-
Exceptions are usually things a system needs to recover from or stop. Eg: Memory issue, DB unreachable
-
Errors are simply the undesirable output of a function. A lot of modern programming languages have embraced this idea.
-
Centralize elevation of Error to Exception in 1 place instead of everywhere.
- It is not possible to write 100% Pure functional code in JS. We can surely write JS in a functional STYLE.
- Functional programming is more of a thinking style than a programming style.
- The constraints of FP, helps us write more declarative and safe code
- Videos: FunFunFunction FP Series
- Video: Functional Programming in 40 minutes
- Video: Plain Functional Programming by Martin Ordersky
- Repo: Functional Programming Lite by Kyle Simpson
- Book: Mastering Functional Programming in JavaScript