GithubHelp home page GithubHelp logo

functional-programming-javascript's Introduction

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:

//  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

Edit on Codepen

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.

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:

const isZero = n => n === 0;
const a = [0, 1, 0, 3, 4, 0];
console.log(a.filter(isZero)); // [0, 0, 0]

Edit on Codepen

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

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

const getSalutation = (hour) => hour < 12 ? "Good Morning" : "Good Afternoon";
console.log(getSalutation(10)); // Good Morning

Edit on Codepen

Higher Order Functions

A function that accepts another function as a parameter, or returns another function.

For example:

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]]

Edit on Codepen

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 state

For example:

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;
};

Edit on Codepen

Recursion

Recursion is the ability to call a function from within itself.

For example:

function countUp(n) {
  console.log(n);
  if(n < 10) countUp(n+1);
}

countUp(1);

Edit on Codepen

Anonymous Functions

Anonymous function is the function that was declared without any named identifier to refer to it.

For example:

// 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.

// 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

Edit on Codepen

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:

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 = `
<p>every: ${everyResult}</p>
<p>some: ${someResult}</p>
<p>find: ${JSON.stringify(findResult)}</p>
<p>filter: ${JSON.stringify(filterResult)}</p>
<p>map: ${JSON.stringify(mapResult)}</p>
<p>reduce: ${JSON.stringify(reduceResult)}</p>
<p>reverse: ${JSON.stringify(reverseResult)}</p>
<p>sort: ${JSON.stringify(sortResult)}</p>`;

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:

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

Edit on Codepen

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.

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

Edit on Codepen

functional-programming-javascript's People

Contributors

bunlong avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.