# Functional JavaScript: Immutability

This is an excerpt from our book, Learning React. The second edition will be coming out this summer!

When you start to explore React, you'll likely notice that the topic of functional programming comes up a lot. Functional techniques are being used more and more in JavaScript projects, particularly React projects.

It's likely that you have already written functional JavaScript code without thinking about it. If you've mapped or reduced an array, then you're already on your way to becoming a functional JavaScript programmer. Functional programming techniques are core not only to React but to many of the libraries in the React ecosystem as well.

If you are wondering where this functional trend came from, the answer is the 1930s, with the invention of lambda calculus, or λ-calculus. Dana S. Scott, "λ-Calculus: Then & Now". Functions have been a part of calculus since it emerged in the 17th century. Functions can be sent to functions as arguments or returned from functions as results.  More complex functions, called higher-order functions, can manipulate functions and use them as either arguments or results or both. In the 1930s, Alonzo Church was at Princeton experimenting with these higher-order functions when he invented lambda calculus.

In the late 1950s, John McCarthy took the concepts derived from λ-calculus and applied them to a  new programming language called Lisp.  Lisp implemented the concept of higher-order functions and functions as first-class members or first-class citizens. A function is considered a first-class member when it can be declared as a variable and sent to functions as an argument. These functions can even be returned from functions.

Let's take a look at one of the concepts that is often associated with functional JavaScript: immutability.

To mutate is to change, so to be immutable is to be unchangeable. In a functional program, data is immutable. It never changes.

If you need to share your birth certificate with the public, but want to redact or remove private information, you essentially have two choices: you can take a big Sharpie to your original birth certificate and cross out your private data, or you can find a copy machine. Finding a copy machine, making a copy of your birth certificate, and writing all over that copy with that big Sharpie would be preferable. This way you can have a redacted birth certificate to share and your original that is still intact.

This is how immutable data works in an application. Instead of changing the original data structures, we build changed copies of those data structures and use them instead.

To understand how immutability works, let's take a look at what it means to mutate data. Consider an object that represents the color `lawn`:

``let color_lawn = {  title: "lawn",  color: "#00FF00",  rating: 0};``

We could build a function that would rate colors, and use that function to change the rating of the `color` object:

``function rateColor(color, rating) {  color.rating = rating;  return color;}console.log(rateColor(color_lawn, 5).rating); // 5console.log(color_lawn.rating); // 5``

In JavaScript, function arguments are references to the actual data. Setting the color's rating like this changes or mutates the original color object. (Imagine if you tasked a business with redacting and sharing your birth certificate and they returned your original birth certificate with black marker covering the important details. You'd hope that a business would have the common sense to make a copy of your birth certificate and return the original unharmed.) We can rewrite the `rateColor` function so that it does not harm the original goods (the `color` object):

``const rateColor = function(color, rating) {  return Object.assign({}, color, { rating: rating });};console.log(rateColor(color_lawn, 5).rating); // 5console.log(color_lawn.rating); // 4``

Here, we used `Object.assign` to change the color rating. `Object.assign` is the copy machine. It takes a blank object, copies the color to that object, and overwrites the rating on the copy. Now we can have a newly rated color object without having to change the original.

We can write the same function using an arrow function along with the object spread operator. This `rateColor` function uses the spread operator to copy the color into a new object and then overwrite its rating:

``const rateColor = (color, rating) => ({  ...color,  rating});``

This version of the `rateColor` function is exactly the same as the previous one. It treats color as an immutable object, does so with less syntax, and looks a little bit cleaner. Notice that we wrap the returned object in parentheses. With arrow functions, this is a required step since the arrow can't just point to an object's curly braces.

Let's consider an array of color names:

``let list = [  { title: "Rad Red" },  { title: "Lawn" },  { title: "Party Pink" }];``

We could create a function that will add colors to that array using `Array.push`:

``const addColor = function(title, colors) {  colors.push({ title: title });  return colors;};console.log(addColor("Glam Green", list).length); // 4console.log(list.length); // 4``

However, `Array.push` is not an immutable function. This `addColor` function changes the original array by adding another field to it. In order to keep the `colors` array immutable, we must use `Array.concat` instead:

``const addColor = (title, array) => array.concat({ title });console.log(addColor("Glam Green", list).length); // 4console.log(list.length); // 3``

`Array.concat` concatenates arrays. In this case, it takes a new object, with a new color title, and adds it to a copy of the original array.

You can also use the spread operator to concatenate arrays in the same way it can be used to copy objects. Here is the emerging JavaScript equivalent of the previous `addColor` function:

``const addColor = (title, list) => [...list, { title }];``

This function copies the original list to a new array and then adds a new object containing the color's title to that copy. It is immutable.

### Data Transformations #

How does anything change in an application if the data is immutable? Functional programming is all about transforming data from one form to another. We will produce transformed copies using functions. These functions make our code less imperative and thus reduce complexity.

You do not need a special framework to understand how to produce one dataset that is based upon another. JavaScript already has the necessary tools for this task built into the language. There are two core functions that you must master in order to be proficient with functional JavaScript: `Array.map` and `Array.reduce`.

In this section, we will take a look at how these and some other core functions transform data from one type to another.

Consider this array of high schools:

``const schools = ["Yorktown", "Washington & Lee", "Wakefield"];``

We can get a comma-delimited list of these and some other strings by using the `Array.join` function:

``console.log(schools.join(", "));// "Yorktown, Washington & Lee, Wakefield"``

`Array.join` is a built-in JavaScript array method that we can use to extract a delimited string from our array. The original array is still intact; `join` simply provides a different take on it. The details of how this string is produced are abstracted away from the programmer.

If we wanted to create a function that creates a new array of the schools that begin with the letter "W", we could use the `Array.filter` method:

``const wSchools = schools.filter(school => school[0] === "W");console.log(wSchools);// ["Washington & Lee", "Wakefield"]``

`Array.filter` is a built-in JavaScript function that produces a new array from a source array. This function takes a predicate as its only argument. A predicate is a function that always returns a Boolean value: `true` or `false`. `Array.filter` invokes this predicate once for every item in the array. That item is passed to the predicate as an argument and the return value is used to decide if that item shall be added to the new array. In this case, `Array.filter` is checking every school to see if its name begins with a "W".

When it is time to remove an item from an array we should use `Array.filter` over `Array.pop` or `Array.splice` because `Array.filter` is immutable. In this next sample, the `cutSchool` function returns new arrays that filter out specific school names:

``const cutSchool = (cut, list) => list.filter(school => school !== cut);console.log(cutSchool("Washington & Lee", schools).join(", "));// "Yorktown, Wakefield"console.log(schools.join("\n"));// Yorktown// Washington & Lee// Wakefield``

In this case, the `cutSchool` function is used to return a new array that does not contain "Washington & Lee". Then the `join` function is used with this new array to create a star-delimited string out of the remaining two school names. `cutSchool` is a pure function. It takes a list of schools and the name of the school that should be removed and returns a new array without that specific school.

Another array function that is essential to functional programming is `Array.map`. Instead of a predicate, the `Array.map` method takes a function as its argument. This function will be invoked once for every item in the array, and whatever it returns will be added to the new array:

``const highSchools = schools.map(school => `\${school} High School`);console.log(highSchools.join("\n"));// Yorktown High School// Washington & Lee High School// Wakefield High Schoolconsole.log(schools.join("\n"));// Yorktown// Washington & Lee// Wakefield``

In this case, the `map` function was used to append "High School" to each school name. The `schools` array is still intact.

In the last example, we produced an array of strings from an array of strings. The `map` function can produce an array of objects, values, arrays, other functions—any JavaScript type. Here is an example of the `map` function returning an object for every school:

``const highSchools = schools.map(school => ({ name: school }));console.log(highSchools);// [// { name: "Yorktown" },// { name: "Washington & Lee" },// { name: "Wakefield" }// ]``

An array containing objects was produced from an array that contains strings.

If you need to create a pure function that changes one object in an array of objects, `map` can be used for this, too. In the following example, we will change the school with the name of "Stratford" to "HB Woodlawn" without mutating the `schools` array:

``let schools = [  { name: "Yorktown" },  { name: "Stratford" },  { name: "Washington & Lee" },  { name: "Wakefield" }];let updatedSchools = editName("Stratford", "HB Woodlawn", schools);console.log(updatedSchools[1]); // { name: "HB Woodlawn" }console.log(schools[1]); // { name: "Stratford" }``

The `schools` array is an array of objects. The `updatedSchools` variable calls the `editName` function and we send it the school we want to update, the new school, and the `schools` array. This changes the new array but makes no edits to the original:

``const editName = (oldName, name, arr) =>  arr.map(item => {    if (item.name === oldName) {      return {        ...item,        name      };    } else {      return item;    }  });``

Within `editName`, the `map` function is used to create a new array of objects based upon the original array.  The `editName` function can be written entirely in one line. Here's an example of the same function using a shorthand `if/else` statement:

``const editName = (oldName, name, arr) =>  arr.map(item => (item.name === oldName ? { ...item, name } : item));``

If you need to transform an array into an object, you can use `Array.map` in conjunction with `Object.keys`. `Object.keys` is a method that can be used to return an array of keys from an object.

Let's say we needed to transform `schools` object into an array of schools:

``const schools = {  Yorktown: 10,  "Washington & Lee": 2,  Wakefield: 5};const schoolArray = Object.keys(schools).map(key => ({  name: key,  wins: schools[key]}));console.log(schoolArray);// [// {// name: "Yorktown",// wins: 10// },// {// name: "Washington & Lee",// wins: 2// },// {// name: "Wakefield",// wins: 5// }// ]``

In this example, `Object.keys` returns an array of school names, and we can use `map` on that array to produce a new array of the same length. The `name` of the new object will be set using the key, and `wins` is set equal to the value.

So far we've learned that we can transform arrays with `Array.map` and `Array.filter`. We've also learned that we can change arrays into objects by combining `Object.keys` with `Array.map`. The final tool that that we need in our functional arsenal is the ability to transform arrays into primitives and other objects.

The `reduce` and `reduceRight` functions can be used to transform an array into any value, including a number, string, boolean, object, or even a function.

Let's say we needed to find the maximum number in an array of numbers. We need to transform an array into a number; therefore, we can use `reduce`:

``const ages = [21, 18, 42, 40, 64, 63, 34];const maxAge = ages.reduce((max, age) => {  console.log(`\${age} > \${max} = \${age > max}`);  if (age > max) {    return age;  } else {    return max;  }}, 0);console.log("maxAge", maxAge);// 21 > 0 = true// 18 > 21 = false// 42 > 21 = true// 40 > 42 = false// 64 > 42 = true// 63 > 64 = false// 34 > 64 = false// maxAge 64``

The `ages` array has been reduced into a single value: the maximum age, `64`. `reduce` takes two arguments: a callback function and an original value. In this case, the original value is `0`, which sets the initial maximum value to `0`. The callback is invoked once for every item in the array. The first time this callback is invoked, `age` is equal to `21`, the first value in the array, and `max` is equal to `0`, the initial value. The callback returns the greater of the two numbers, `21`, and that becomes the `max` value during the next iteration. Each iteration compares each `age` against the `max` value and returns the greater of the two. Finally, the last number in the array is compared and returned from the previous callback.

If we remove the `console.log` statement from the preceding function and use a shorthand `if/else` statement, we can calculate the max value in any array of numbers with the following syntax:

``const max = ages.reduce(  (max, value) => (value > max ? value : max),  0);``

Sometimes we need to transform an array into an object. The following example uses `reduce` to transform an array that contains colors into a hash:

``const colors = [  {    id: "xekare",    title: "rad red",    rating: 3  },  {    id: "jbwsof",    title: "big blue",    rating: 2  },  {    id: "prigbj",    title: "grizzly grey",    rating: 5  },  {    id: "ryhbhsl",    title: "banana",    rating: 1  }];const hashColors = colors.reduce((hash, { id, title, rating }) => {  hash[id] = { title, rating };  return hash;}, {});console.log(hashColors);// {// "xekare": {// title:"rad red",// rating:3// },// "jbwsof": {// title:"big blue",// rating:2// },// "prigbj": {// title:"grizzly grey",// rating:5// },// "ryhbhsl": {// title:"banana",// rating:1// }// }``

In this example, the second argument sent to the `reduce` function is an empty object. This is our initial value for the hash. During each iteration, the callback function adds a new key to the hash using bracket notation and sets the value for that key to the `id` field of the array. `Array.reduce` can be used in this way to reduce an array to a single value—in this case, an object.

We can even transform arrays into completely different arrays using `reduce`.  Consider reducing an array with multiple instances of the same value to an array of unique values. The `reduce` method can be used to accomplish this task:

``const colors = ["red", "red", "green", "blue", "green"];const uniqueColors = colors.reduce(  (unique, color) =>    unique.indexOf(color) !== -1 ? unique : [...unique, color],  []);console.log(uniqueColors);// ["red", "green", "blue"]``

In this example, the `colors` array is reduced to an array of distinct values. The second argument sent to the `reduce` function is an empty array. This will be the initial value for `distinct`. When the `distinct` array does not already contain a specific color, it will be added. Otherwise, it will be skipped, and the current `distinct` array will be returned.

`map` and `reduce` are the main weapons of any functional programmer, and JavaScript is no exception. The ability to create one dataset from another is a required skill and is useful for any type of programming paradigm.