Categories
Functional Javascript

Functional Programming Features in JavaScript

JavaScript is an easy to learn programming language. It also uses lots of functional programming features that make our lives easier.

In this article, we’ll take a look at some functional programming features of JavaScript that we can use in our code.

What is Functional Programming?

Functional programming is a programming paradigm where we treat computations as an evaluation of mathematical functions. This means we avoid changing state and mutating data,

It’s a declarative programming paradigm where we only tell how the program should run in a high level to create our program rather than writing instructions to tell the computer how to run a program step by step.

Functional programming emphasizes the use of pure functions, where a function’s arguments determine its output.

Also, side effects should be eliminated in functions since they make a function impure.

Eliminating side effects also make functions easier to test since we only have to put in inputs and check its output rather than also having to check what the side effects have done.

Lazy Evaluation

Lazy evaluation is evaluating values only when the value is needed. In JavaScript, we can do that by returning a value in a function and then invoking the function when needed.

For instance, we can write the following code to do that:

const lazy = () => 2 + 1

In the code above, we put our value 3 as the return value of the lazy function.

Now we only get the value when we need it by calling the lazy function.

This is opposed to setting 3 as a variable as we do below:

let val = 2 + 1;

The code above is evaluated immediately rather than waiting for the lazy function to be evaluated before returning the value.

Lazy evaluations avoid repeated evaluation, which makes our code more efficient than evaluating expressions immediately.

We can also implement lazy evaluation with functions by return the function instead of assigning a function directly to a variable.

For instance, we can write the following to create a lazily evaluated function as follows:

const lazyAdd = (a, b) => () => a + b;
const add = lazyAdd(1, 2);
const result = add();

In the code above, we have the lazyAdd function, which returns a function that returns the 2 parameters added together.

Then when we call the lazyAdd function with 2 numbers, we return a function that’ll return the 2 numbers added together instead of returning the evaluated expression directly.

Then when we call add , we actually return 1 and 2 added together.

This again delays the evaluation of the sum until it’s needed. And it’s opposed to the following code:

const add = (a, b) => a + b;
const result = add(1, 2);

which evaluates the 2 arguments added together immediately.

Monoid

In functional programming, a monoid is a set of elements that has 3 special properties when combined with an operation named concat .

Monoids have the following characteristics:

  • The operation must combine 2 values into the 3rd value of the same set. If a and b are part of the set, then concat(a, b) should also be part of the same set.
  • The operation must be associative. That is, concat(a, concat(b, c)) should be the same as concat(concat(a, b), c) .
  • The set must have a neutral element regarding its operation. If the neutral element is combined with any other value, it shouldn’t change it. That is, concat(a, neutral) === concat(neutral, a) .

There’re many examples of monoids in JavaScript. The most common are strings and numbers.

For instance, with numbers, we can check that they meet the 3 properties above.

Given that a is 1 and b is 2, and the concat operator is + , we can check that the first property is met by writing:

a + b === 3

a and b are both numbers and 3 is a number, so they’re in the same set, and the first criterion is met.

Then we can check associativity as follows:

((a + b) + 3) === (a + (b + 3))

Since that returns true , we can group them in the order we want, so + with numbers is associative.

We can check if a set has a neutral element by picking 0 as the neutral element.

For instance:

a + 0 === 0 + a

returns true , so we know that the set of numbers has a neutral element, which is 0. Therefore, we know that there’s a neutral element when adding numbers.

Therefore, the addition operation with numbers is a monoid.

Monoids are useful because it lets us compose multiple simple operations to create complex behavior out of them, without having to introduce new concepts in our code.

They always return the elements in the same set, so we can continue composing these elements and operations together.

Associativity lets us disregard the order of the compose and still get the same result, reducing the cognitive load that we need when we need to compose multiple operations.

Conclusion

JavaScript exhibits some functional programming characteristics. This makes writing code more like defining and using mathematical functions.

For instance, things can be lazily evaluated to increase efficiency and it has monoids like number addition. Monoids are useful because of the easy composition of multiple operations.

Functional programming emphasizes pure functions, which are easier to test.

Categories
Functional Javascript

Manipulate JavaScript Arrays the Functional Way

Functional programming is a programming paradigm which states that we create computations as the evaluation of functions and avoid changing state and mutable data.

To write programs in a functional way, we use pure functions and immutable data structures.

In JavaScript, we can easily apply functional principles to arrays by using its built-in array methods.

In this article, we’ll look at the array methods that let us manipulate them in a functional way.

Filtering Items

We can use the filter method to return an array with entries from the original array that has the condition that the callback of the filter method returns.

For example, if we have the following array:

const store = [{
    name: "Apple",
    price: 1
  },
  {
    name: "Banana",
    price: 2
  },
  {
    name: "Grape",
    price: 1.2
  }
];

We can get the items that have price less than 2 as follows:

const cheapItems = store.filter(s => s.price < 2);

Then we get the following for cheapItems:

[
  {
    "name": "Apple",
    "price": 1
  },
  {
    "name": "Grape",
    "price": 1.2
  }
]

Using the filter method fits with the functional paradigm since the function is pure, given the same array and same condition, we always get the same results returned.

It also doesn’t change the existing elements of the array that it’s called on, which means we can’t accidentally change anything from the original array.

Mapping Array Objects

map is used to map entries of an array into something else. It’s frequently used to convert and transform data. Using map fits with the functional programming paradigm because again it’s a pure function that gives the same outputs for the given inputs, and it doesn’t change the original array.

As long as the function we pass into the map function to combine the values is pure, the map method should also be pure since it just calls this callback function and returns the updated values into a new array.

For example, given the following array:

const volumesInLiters = [{
    name: "Milk",
    volumeInLiters: 1
  },
  {
    name: "Apple Juice",
    volumeInLiters: 2
  },
  {
    name: "Orange Joice",
    volumeInLiters: 1.2
  }
];

We can add the volumeInQuarts field to each entry of the object and set the volume in quarts to as the value of each by writing:

const volumesInQuarts = volumesInLiters.map(v => {
  v = {
    ...v,
    volumeInQuarts: v.volumeInLiters * 1.057
  };
  return v;
})

We convert v.volumeInLiters * 1.057 and set it to volumeInQuarts for each entry.

Then we get:

[
  {
    "name": "Milk",
    "volumeInLiters": 1,
    "volumeInQuarts": 1.057
  },
  {
    "name": "Apple Juice",
    "volumeInLiters": 2,
    "volumeInQuarts": 2.114
  },
  {
    "name": "Orange Joice",
    "volumeInLiters": 1.2,
    "volumeInQuarts": 1.2684
  }
]

Using Reduce to Combine Values of Array Entries

Like filter and map, reduce also fits with the functional paradigm since we use it to gather entries of an array and return one value by the way that we specify.

As long as the function we pass into the reduce function to combine the values is pure, the reduce method should be pure. The function just calls the callback function we pass into reduce to compute the combined value.

For example, given the following array:

const store = [{
    name: "Apple",
    price: 1
  },
  {
    name: "Banana",
    price: 2
  },
  {
    name: "Grape",
    price: 1.2
  }
];

We can write the following to get the total price of all items:

const totalPrice = store.map(s => s.price).reduce((subtotal, b) => subtotal + b, 0);

We have to use map to map all the entries in the store array to price numbers. Then we can use the reduce method to add the new value to subtotal.

Then we should get 4.2 for totalPrice, which is the total of all the prices of the 3 items in store.

The second argument of reduce is the starting value of the reduction, or combining the values into one.

Conclusion

The filter, map, and reduce array methods are the main methods for manipulating arrays in a functional manner. They all return values and don’t change the array that it’s called on. This makes it difficult to unintentionally change the values.

filter returns an array that meets the condition that we return in the callback that we pass in.

map returns a new array that has the values of the original array mapped to new values in a way that we specify.

reduce combines the values of array entries into one by taking a callback function that we pass in to do the combining and returns the combined value.

The functions are pure if we pass in pure functions to them as callbacks since they just call the functions that we pass in to do the manipulation.

Categories
Functional Javascript

Functional Programming Concepts in JavaScript

Functional programming is a programming paradigm which states that we create computation as the evaluation of functions and avoid changing state and mutable data.

In JavaScript, we can apply these principles to make our programs more robust and create fewer bugs.

In this article, we’ll look at how to apple some functional programming principles in our JavaScript programs, including pure functions and creating immutable objects.

Pure Functions

Pure functions are functions that always return the same output given the same set of inputs.

We should use pure functions as much as possible because they’re easier to test and the output is always predictable given a set of inputs.

Also, pure functions don’t create any side effects, which means that it does change anything outside the function.

An example of a pure function would be the following add function:

const add = (a, b) => a + b;

This function is a pure function because if we pass in 2 numbers, we’ll get the 2 numbers added together returned.

It doesn’t do anything outside the function, and it doesn’t have values that change the returned value inside the function.

Example of functions that aren’t pure functions include:

let x;
const setX = val => x = val;

setX isn’t a pure function because it sets the value of x which is outside the function. This is called a side effect.

A side effect is a state change that’s observed outside the called function other than its returned value. setX sets a state outside the function, so it commits a side effect.

Another example would be the following:

const getCurrentDatePlusMs = (milliseconds) => +new Date() + milliseconds;

getCurrentDatePlusMs returns a value that depends on +new Date() which always changes, so we can check the value of it with tests easily. It’s also hard to predict the return value given the input since it always changes.

getCurrentDatePlusMs isn’t a pure function and it’s also a pain to maintain and test because of its ever-changing return value.

To make it pure, we should put the Date object outside as follows:

const getCurrentDatePlusMs = (date, milliseconds) => +date + milliseconds;

That way, given the same date and milliseconds, we’ll always get the same results.

Immutability

Immutability means that a piece of data can’t be changed once it’s defined.

In JavaScript, primitive values are immutable, this includes numbers, booleans, strings, etc.

However, there’s no way to define an immutable object in JavaScript. This means that we have to be careful with them.

We have the const keyword, which should create a constant by judging from the name of it, but it doesn’t. We can’t reassign new values to it, and we can’t redefine a constant with the same name.

However, the object assigned to const is still mutable. We can change its properties’ values, and we can remove existing properties. Array values can be added or removed.

This means that we need some other way to make objects immutable.

Fortunately, JavaScript has the Object.freeze method to make objects immutable. It prevents property descriptors of an object from being modified. Also, it prevents properties from being deleted with the delete keyword.

Once an object is frozen, it can’t be undone. To make it mutable again, we have to copy the object to another variable.

It applies these changes to the top level of an object. So if our object has nesting, then it won’t be applied to the nested objects.

We can define a simple recursive function to do freeze level of an object:

const deepFreeze = (obj) => {
  for (let prop of Object.keys(obj)) {
    if (typeof obj[prop] === 'object') {
      Object.freeze(obj[prop]);
      deepFreeze(obj[prop]);
    }
  }
}

The function above goes through every level of an object and calls Object.freeze on it. This means it makes the whole nested object immutable.

We can also make a copy of an object before manipulating it. To do this, we can use the spread operator, which works with objects since ES2018.

For example, we can write the following function to make a deep copy of an object:

const deepCopy = (obj, copiedObj) => {
  if (!copiedObj) {
    copiedObj = {};
  }

  for (let prop of Object.keys(obj)) {
    copiedObj = {
      ...copiedObj,
      ...obj
    };
    if (typeof obj[prop] === 'object' && !copiedObj[prop]) {
      copiedObj = {
        ...copiedObj,
        ...obj[prop]
      };
      deepCopy(obj[prop], copiedObj);
    }
  }
  return copiedObj;
}

In the code above, we create a new copiedObj object to hold the properties of the copied object if it doesn’t exist yet, which shouldn’t in the first call.

Then we loop through each property of the obj object and then apply the spread operator to copiedObj and obj to make a copy of the values at a given level. Then we do this recursively at every level until we went through every level, then we return the final copiedObj .

We only apply the spread operator if the property doesn’t exist at that level yet.

How do we know that this works? First, we can check if properties of each value are the same, which it is if we run console.log on it. Then we can also check with the === if the copied object has the same reference as the original object.

For example, if we have:

const obj = {
  foo: {
    bar: {
      bar: 1
    },
    a: 2
  }
};

Then we can check by writing:

const result = deepCopy(obj);
console.log(result);

To check the content of result .

We should get:

{
  "foo": {
    "bar": {
      "bar": 1
    },
    "a": 2
  }
}

This is the same as obj . If we run:

console.log(result === obj);

we get false , which means the 2 aren’t referencing the same object. This means that they’re a copy of each other.

Pure functions and immutability are important parts of functional programming. These concepts are popular for a reason. They make outputs predictable and make accidental state changes harder.

Pure functions are predictable since they return the same output for the same set of inputs.

Immutable objects are good because it prevents accidental changes. Primitive values in JavaScript are immutable, but objects are not. We can freeze it with the Object.freeze method to prevent changes to it and we can also make a copy of it recursively with the spread operator.