JavaScript Lessons: Arrays

Friday, March 26th 2021 (1 month ago)

Alex Casillas@alexvcasillas

Welcome to the first post of this new series about JavaScript that we call JavaScript Lessons, a place where you will be able to learn the basics of JavaScript to become a better developer o refresh some knowledge of the most used topics out there.

Let's start with the basics. If you're a more experienced developer, you can skip this initial part or maybe stay and refresh some knowledge.

What is an Array?

An Array in JavaScript is a global object used in the construction of lists.

The prototype, or the core functionality, of the Array includes methods to perform reading, writing, listing and mutation of the elements within the list. The type and the length of an array can change in any time and the data can be stored in non-contiguous positions.

Arrays in JavaScript are zero-indexed, meaning that the first position of an array is always zero.

Creating an array

Creating an array with JavaScript takes little effort.

const people = ['Alex', 'Daniel', 'Rafael', 'May'];

The people variable now holds an array with 4 elements of type string within it, indexed as follows:

  1. Alex
  2. Daniel
  3. Rafael
  4. May

As you can see, the first position of the array, index zero, corresponds to the string Alex. The length of this array is four.

If you would like to create an empty array instead, you will have to:

const people = [];

This will create an empty array. The length of this array is zero.

Getting an array's length

To get an array's length you can use the length property:

const people = ['Alex', 'Daniel', 'Jake', 'May'];

people.length; // 4

Accessing an element by it's index

In order to access an element within an array by it's index, we should do as follows:

const people = ['Alex', 'Daniel', 'Jake', 'May'];

people[1]; // Daniel

If you try to access an element by it's index and there's no element at the given index, you will get an undefined in return.

const people = ['Alex', 'Daniel', 'Jake', 'May'];

people[4]; // undefined

If you have a dynamic array and you want to access the last element in the array, you can use the length property to get the number of elements in the array and subtract 1, because if you remember, arrays are zero-indexed, that's why we need to subtract 1 from the length of the array.

const people = ['Alex', 'Daniel', 'Jake', 'May'];

people[people.length - 1]; // May

Let's see what happens if you don't subtract 1 from the people.length property.

const people = ['Alex', 'Daniel', 'Jake', 'May'];

people[people.length]; // undefined

people.length will return 4 and the 4th position of the people array is, in fact, undefined.

Iterating over an array

There are a few ways to iterate over an array, we are going to learn how to iterate with a for loop and a forEach callback function. There are also a few others but we will get into more detail about other possibilities of iterating an array later on.

Iterating over an array with a for loop

Iterating an array with a for loop is, by far, the most efficient and fastest way to iterate over an array.

First, we should get the length of the array.

const people = ['Alex', 'Daniel', 'Jake', 'May'];
const amountOfPeople = people.length; // 4;

Now we need to construct the for loop. This is one of the most basic things that you will learn when studying computer science.

for (let index = 0; index <= amountOfPeople - 1; index++) {}

Let's take a look at the signature of a for loop.

  • for: this is a reserver word in JavaScript used to declare a for loop.
  • let index = 0: this is a variable declaration and it's going to be used to hold the current iteration index.
  • index <= amountOfPeople - 1: this is the predicate used to determine if the loop should keep being executed or finish the iterations, if the predicate is equal to true it will continue executing, if the predicate is equal to false it will finish executing.
  • index++: this the action that will be executed when an iteration finishes, commonly, you use this to increase the indexing variable by one or by any number that you'd like to.

Now let's glue all together to construct a for loop that will display all of the persons names in the console of your browser.

const people = ['Alex', 'Daniel', 'Jake', 'May'];
const amountOfPeople = people.length; // 4;

for (let index = 0; index <= amountOfPeople - 1; index++) {
  console.log(people[index]);
}

If you execute this code in your Node terminal or in a REPL, you should see an output like the following:

  1. Alex
  2. Daniel
  3. Jake
  4. May

Iterating over an array with a forEach callback function

Iterating an array with a forEach callback is not as efficient as the for loop but someone could say that it's more visually appealing and readable, if performance is not important and you're aiming for readability, then you should go with forEach. But remember, that the forEach callback function cannot be asynchronous and if you try to async/await it, it will definitely give you more than one or two headaches.

Let's take a look at how to use the forEach callback function.

const people = ['Alex', 'Daniel', 'Jake', 'May'];

people.forEach(function (element, index, array) {
  console.log(element);
});

Now let's take a look at the signature of a forEach callback function as we did with the for loop.

  • people.forEach(): as you can see here, the .forEach() is a method from the Array prototype (core functionality) and it's available to you because the people variable is an Array object.
  • function(element, index, array): is the callback function that will be called for each of the elements within the array. This function will get 3 parameters passed along for you to make use of them, this parameters are:
    1. element: the current element of the array in this iteration.
    2. index: the current index of this iteration.
    3. array: the whole array will be passed to this property just in case you'd need to access it for something.

As you can see, it might be a little more readable than the for loop but if performance is not important, feel free to depend on it as needed. You can even make it shorter with an arrow function with implicit return πŸ™ƒ

const people = ['Alex', 'Daniel', 'Jake', 'May'];

people.forEach((element, index, array) => console.log(element));

Adding elements to an array

In order to add elements to an array we have multiple ways, we can push an element into the last position, we can store an element into a specific array's position based on an index or we can unshift an element into the first position of the array. Let's take a look at some of those methods for adding elements to an array.

push elements into an array

We are going to use the push() method from the Array object to add an element to the end of an array. Let's say we have an array of fruits that contains an apple 🍎, a pear 🍐, a lemon πŸ‹, and we did some groceries and we would like to add a banana too 🍌, we don't care where to put it, so we're just going to push it in the end.

let fruit = ['🍎', '🍐', 'πŸ‹'];

fruit.push('🍌');

The fruit array will now contain an apple 🍎, a pear 🍐, a lemon πŸ‹ and a banana 🍌.

Storing elements based on an index position

We're going to use the index position of an array to store the watermelon πŸ‰ we just bought into a specific place in the fruit array that we previously created.

let fruit = ['🍎', '🍐', 'πŸ‹', '🍌'];

fruit[4] = 'πŸ‰';

The fruit array will now contain an apple 🍎, a pear 🍐, a lemon πŸ‹, a banana 🍌 and, in the 4th position of the array, a watermelon πŸ‰.

Let's imagine that we have purchased the watermelon πŸ‰ but we don't have any more space in the fridge so we need to take out a fruit in order to store the watermelon πŸ‰. How do we do this? Let's assume we don't want any more lemons πŸ‹.

let fruit = ['🍎', '🍐', 'πŸ‹', '🍌'];

fruit[2] = 'πŸ‰';

After this change, the fruit array will now contain an apple 🍎, a pear 🍐, a watermelon πŸ‰ and a banana 🍌. The lemon πŸ‹ is gone because we have used it's index position to tell the array that in that particular position we would like to have a watermelon πŸ‰ instead of a lemon πŸ‹.

unshift elements into an array

We are going to use the unshift() method from the Array object to add an element to the beginning of the array. Let's say we still have this fruit array but we want to add more fruit to it because we have purchased a new fruit, an orange 🍊, and we would like to save it for the last because it's the newest fruit and you should always it the fruit that you've purchased before the new fruit.

let fruit = ['🍎', '🍐', 'πŸ‰', '🍌'];

fruit.unshift('🍊');

The fruit array will now contain an orange 🍊, an apple 🍎, a pear 🍐, a watermelon πŸ‰ and a banana 🍌.

Removing elements from an array

We are going to use the pop() method from the Array object to remove the last element from an array. Let's say we still have this fruit array but we want to start eating fruit but we want to eat the ones we purchased recently (not a good idea with fruit!).

let fruit = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];

fruit.pop();

The fruit array will now contain an orange 🍊, an apple 🍎, a pear 🍐 and a watermelon πŸ‰, but the banana will be gone because we have just ate it πŸ˜‹.

Removing various elements by position

With the splice(from, amount) method from the Array object we can remove a subset of the elements on the array by an index range. We provide the from index where the subtraction will start and the amount of elements that we would like to subtract from the starting point.

let fruit = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];

let removedElements = fruit.splice(1, 3); // ['🍎', '🍐', 'πŸ‰']

fruit; // ['🍊', '🍌'];

The splice method takes out the given elements and returns them so you can use them separately as a new array.

πŸ“£ Heads up! the splice method mutates the original array and this could lead to bugs in your code. You should try to achieve immutability in your code to easily identify bugs.

Finding the index of an element in an array

Imagine that you want to know where the apples 🍎 are located in your fridge, how would you do this? Thankfully, the Array object has a very handy method to tell you the index of an element within an array, that method is indexOf and given an element, it will return you the index of that element within the array or -1 if the element is not found in the array.

let fruit = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];

let appleIndex = fruits.indexOf('🍎'); // 1

Now we want to find where the watermelon πŸ‰ is at!

let fruit = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];

let watermelonIndex = fruits.indexOf('πŸ‰'); // 3

Do we have any lemons πŸ‹?

let fruit = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];

let lemonIndex = fruits.indexOf('πŸ‹'); // -1

We don't have any lemons πŸ‹ on the fridge and that's why the lemonIndex variable will hold a -1.

πŸ“£ Heads up! The indexOf method will return the index of the first element that matches in the array. If you have various elements that are the same, the index that will be returned will be the one that matches first from index 0 to index n.

Another way of finding the index of an element in an array

Imagine that you know you have an apple 🍎 but you don't actually know where it's located on the fridge. How would you do this? Thankfully, we have the findIndex(predicate) method in the Array object that will allow you to obtain the index in the array of a given element. This method takes a callback function as the main and only argument as a predicate to check for the element that we would like to obtain it's index, and returns the index of the matching element or -1 if the element is not found in the array.

let fruit = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];

let appleIndex = fruits.findIndex('🍎'); // 1

Where are the lemons πŸ‹ in our fridge?

let fruit = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];

let lemonIndex = fruits.findIndex('πŸ‹'); // -1

πŸ“£ Heads up! The indexOf method will return the index of the first element that matches in the array. If you have various elements that are the same, the index that will be returned will be the one that matches first from index 0 to index n.

Copying an array

Copying arrays is a common use case in many applications an scenarios. Copying arrays is a simple task that can be done in different ways. We can use the slice() method from the Array object to create a copy of the array into a new variable, or we can use the new ES6 spread operator (...) feature to create a copy of the array into a new variable.

Using slice to copy an array

We can use the slice method to duplicate the array. This method doesn't mutate the original array so it's kept intact and therefore, it's immutable and better for avoiding bugs 🐞

let basketOne = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];
let basketTwo = basketOne.slice();

basketOne; // ['🍊', '🍎', '🍐', 'πŸ‰', '🍌']
basketTwo; // ['🍊', '🍎', '🍐', 'πŸ‰', '🍌']

Using slice to copy a part of the array

We can use the slice(start, end) method to copy a section of the array from the start point (inclusive) to the end point (exclusive). This method doesn't mutate the original array so it's kept intact and therefore, it's immutable and better for avoiding bugs 🐞

let basketOne = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];
let basketTwo = basketOne.slice(1, 3);

basketOne; // ['🍊', '🍎', '🍐', 'πŸ‰', '🍌']
basketTwo; // ['🍎', '🍐']

Using spread operator to copy an array

We can use the ES6 spread operator (...) to duplicate an array. This method also doesn't mutate the original array so it's kept intact and therefore, it's immutable and better for avoiding bugs 🐞

let basketOne = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];
let basketTwo = [...basketOne];

basketOne; // ['🍊', '🍎', '🍐', 'πŸ‰', '🍌']
basketTwo; // ['🍊', '🍎', '🍐', 'πŸ‰', '🍌']

As you can see both of the options are equal in result and doesn't differ in performance so it's up to you to decide which one you'd like to use πŸ€—

Concatenating arrays with concat

We can use the concat(Array) method to concatenate multiple arrays together so we can obtain an array that will be the combination (concatenation) of other arrays. This method doesn't mutate any of the original arrays so it's kept intact and therefore, it's immutable and better for avoiding bugs 🐞

let basketOne = ['🍊', '🍎'];
let basketTwo = ['🍐', 'πŸ‰', '🍌'];

let combinedBasket = basketOne.concat(basketTwo);

After using the .concat(array) method on an array and passing the array that will be concatenated, it will return a new array instead of modifying the original array. This way, the combinedBasket will contain the following items: '🍊', '🍎', '🍐', 'πŸ‰', '🍌' and the basketOne and basketTwo will remain intact.

Concatenating arrays with the spread operator

We can use the ES6 spread operator (...) to concatenate multiple arrays together so we can obtain an array that will be the combination (concatenation) of other arrays. This method doesn't mutate any of the original arrays so it's kept intact and therefore, it's immutable and better for avoiding bugs 🐞

let basketOne = ['🍊', '🍎'];
let basketTwo = ['🍐', 'πŸ‰', '🍌'];

let combinedBasket = [...basketOne, ...basketTwo];

After using the ES6 spread operator (...) on an array and spreading both arrays into a new array will make the same effect as using the .concat(array) method. Remember that by spreading an array will not modify the original array. This way, the combinedBasket will contain the following items: '🍊', '🍎', '🍐', 'πŸ‰', '🍌' and the basketOne and basketTwo will remain intact.

Finding al element in the array

With the find(predicate) method from the Array object we can find the first element that matches the predicate that we pass as the argument to the find function. If none of the elements on the array matches the predicate undefined will be returned from the find function.

let basket = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];

let watermelon = basket.find(function (element) {
  return element === 'πŸ‰';
});
let basket = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];

let lemon = basket.find(function (element) {
  return element === 'πŸ‹';
});

lemon; // undefined

We can make this even shorter with arrow functions with implicit returns!

let basket = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];

let watermelon = basket.find((element) => element === 'πŸ‰');
let basket = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];

let lemon = basket.find((element) => element === 'πŸ‹');

lemon; // undefined

Checking some elements in the array

With the some(predicate) method from the Array object we can determine if some of the elements in the array match the given predicate. This method returns true or false depending if there are elements that match the predicate or not. This method also returns false for any predicate on an empty array.

Let's imagine we want to check if we have some apples 🍎 in our fridge. How do we do this?

let fridge = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];

let fridgeHasApples = fridge.some(function (element) {
  return element === '🍎';
});

fridgeHasApples; // true

Let's check if our fridge also has some lemons πŸ‹ in it!

let fridge = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];

let fridgeHasLemons = fridge.some(function (element) {
  return element === 'πŸ‹';
});

fridgeHasLemons; // false

Uh oh! We need to do some groceries because we ran out of lemons πŸ‹!

Checking every element in the array

With the every(predicate) method from the Array object we can determine if every of the elements in the array match the given predicate. This method returns true or false depending if all of the elements match the predicate or not. This method also returns true for any predicate on an empty array.

Let's imagine we want to check if all of the fruit we have in the fridge are apples 🍎. How do we do this?

let fridge = ['🍎', '🍎', '🍎', '🍎', '🍎'];

let everythingIsApple = fridge.every(function (element) {
  return element === '🍎';
});

everythingIsApple; // true

Let's check in a fridge with more fruit diversity!

let fridge = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];

let everythingIsApple = fridge.every(function (element) {
  return element === '🍎';
});

everythingIsApple; // false

Using fill to change elements in an array

With the fill(element, from, to) method from the Array object we can change values within an array.

Let's try to fill our fridge with apples 🍎!

let fridge = ['', '', '', '', ''];

fridge.fill('🍎');

fridge; // ['🍎', '🍎', '🍎', '🍎', '🍎']

Now let's try to fill the fridge with some pears 🍐 but just in the spaces 2 to 4 in the fridge!

let fridge = ['', '', '', '', ''];

fridge.fill('🍐', 1, 3);

fridge; // ['🍎', '🍐', '🍐', '🍐, '🍎']

There are some interesting things you should now about the fill method.

  • If from is not used, it will be 0 (zero) by default.
  • If from is negative, it will be calculated as array.length + from.
  • If to is not used, it will use the array.length by default.
  • If to is negative, it will be calculated as array.length + to.
  • The fill method mutates the array should be used carefully so it won't introduce bugs 🐞.
  • If the element is an object, it will copy its reference and fill the array with references to it.

Sorting elements in an array

With the sort(function(a, b) { }) method from the Array object we can sort the elements within the array. If you don't pass a sorting function as the main and only argument to the sort method, it will use the string value based on it's Unicode position. This method mutates the original array and should be used carefully so it won't introduce bugs 🐞.

let numbers = [4, 2, 3, 5, 1, 6, 9];

numbers.sort(); // [1, 2, 3, 4, 5, 6, 9]

Let's look to another example but this time the array will contain strings.

let fruit = ['bananas', 'lemons', 'apples'];

fruit.sort(); // ["apples", "bananas", "lemons"]

Now we're going to introduce our own compare function so we can make the sort method behave like we want. Let's imagine we have an array with posts, which are objects with the following shape:

let post = {
  title: 'Hello there',
  createdAt: new Date('03/23/2021'),
  content: '...'
};
let posts = [
  { title: 'Hello there 3', createdAt: new Date('05/23/2021'), content: '...' },
  { title: 'Hello there 2', createdAt: new Date('04/23/2021'), content: '...' },
  { title: 'Hello there 4', createdAt: new Date('06/23/2021'), content: '...' },
  { title: 'Hello there 1', createdAt: new Date('03/23/2021'), content: '...' }
];

posts.sort(function (postA, postB) {
  if (postA.createdAt.getTime() === postB.createdAt.getTime()) return 0;
  if (postA.createdAt.getTime() > postB.createdAt.getTime()) return -1;
  if (postA.createdAt.getTime() < postB.createdAt.getTime()) return 1;
});

We have implemented a sorting function to sort the posts by the createdAt property, and because that property contains a Date object, we can use the getTime function of it to retrieve the number of milliseconds elapsed since the Unix Time (January 1st, 1970), then we use this numbers to compare which one is bigger. The sorting function excepts you to return a number in an specific way:

  • If the compare function returns a number less than 0, it places the postA in a lower index than postB.
  • If the compare function returns a number greater than 0, it places the postB in a lower index than postA.
  • If the compare function returns 0, it won't change postA or postB indexes.
  • The compare function always needs to return the same value given a specific pair of elements a and b as well as their arguments.

By knowing this, you can sort the array in any manner you'd like to. In the example above, we're reversing the -1 and 1 and by doing so, we're sorting the array in a descending way.

Map (iterate) over the elements in the array

With the map(function(element, index)) method from the Array object we can iterate over the elements and apply the result of the function call to each of the elements and returns a new array with the results.

Let's imagine we have a basket of fruits, but this time, each of the fruits is gonna be a JavaScript object like the following:

let fruitObject = {
  fruit: '🍎',
  amount: 1
};

The fruitObject will contain two properties, one called fruit that will contain the fruit itself and an amount property that will contain how many of this fruit we have. In the above example, we have one (amount: 1) apple (fruit: '🍎').

Let's fill the fridge with fruit!

let fridge = [
  { fruit: '🍊', amount: 1 },
  { fruit: '🍎', amount: 1 },
  { fruit: '🍐', amount: 1 },
  { fruit: 'πŸ‰', amount: 1 },
  { fruit: '🍌', amount: 1 }
];

Now that we have the fridge full of tasty and juicy fruit πŸ˜‹ lets do some groceries because you should always try to have your fridge full of healthy fruit. We need to consider that we don't have enough room in our fridge for all of the fruit so we're going to buy 5 pieces of each fruit but the watermelon πŸ‰, we only need two of it because it's too big and we won't be able to store all of them in our fridge. How do we do this?

let fridge = [
  { fruit: '🍊', amount: 1 },
  { fruit: '🍎', amount: 1 },
  { fruit: '🍐', amount: 1 },
  { fruit: 'πŸ‰', amount: 1 },
  { fruit: '🍌', amount: 1 }
];

let fridgeFullOfFruit = fridge.map(function (fruitObject) {
  if (fruitObject.fruit !== 'πŸ‰') {
    return {
      fruit: fruitObject.fruit,
      amount: 5
    };
  } else {
    return {
      fruit: fruitObject.fruit,
      amount: 2
    };
  }
});

Let's digest what we've done above. We have created a new variable called fridgeFullOfFruit where we were going to store all of the fruit after doing groceries. Then we map (iterate) over the fruitObjects that are stored on the fridge variable and as we already know, the map method from the Array object it's a callback function and takes up to three arguments:

  1. The element that's currently being iterated.
  2. The index of the iteration.
  3. The array that's being iterated.

In this particular scenario, we're only using the element that's currently being iterated so we can safely ignore the other two arguments, that's why our callback function has the following signature function(fruitObject) {}, because we're only using the current element in the iteration process.

Then we need to create the logic within the function that we want to apply to each of the elements in the array:

if (fruitObject.fruit !== 'πŸ‰') {
  return {
    fruit: fruitObject.fruit,
    amount: 5
  };
} else {
  return {
    fruit: fruitObject.fruit,
    amount: 2
  };
}

We're checking if the fruit property in the fruitObject is not a watermelon πŸ‰ and if it's not, we're going to return a fruitObject with the corresponding fruit and an amount of 5, which is the amount of fruit that we want to purchase for all of the fruits but watermelons πŸ‰ which should be an amount of 2.

For the sake of the example, we've made this code more explicit but we can make use of arrow functions with implicit return and a ternary operator to make this code even more compact.

let fridge = [
  { fruit: '🍊', amount: 1 },
  { fruit: '🍎', amount: 1 },
  { fruit: '🍐', amount: 1 },
  { fruit: 'πŸ‰', amount: 1 },
  { fruit: '🍌', amount: 1 }
];

let fridgeFullOfFruit = fridge.map((fruitObject) => ({
  ...fruitObject,
  amount: fruitObject.fruit !== 'πŸ‰' ? 5 : 2
}));

filter an array to find elements

With the filter(function(element, index)) method from the Array object we can iterate over the elements and return the ones that match the condition implemented on the callback function by returning true or false. This filter method will generate a new array with the results like the map method does.

Let's imagine we have the same fruitObject element that we had before in the map example.

let fruitObject = {
  fruit: '🍎',
  amount: 1
};

Let's fill the fridge with all of the corresponding fruit, but this time, some of them will have an amount of 0 (zero) and we're going to use this amount property to filter which elements we need to purchase so we can refill the fridge with.

let fridge = [
  { fruit: '🍊', amount: 0 },
  { fruit: '🍎', amount: 1 },
  { fruit: '🍐', amount: 0 },
  { fruit: 'πŸ‰', amount: 1 },
  { fruit: '🍌', amount: 0 }
];

Now we need to filter all of this fruitObjects to determine which ones we need to purchase based on the amount property of each of this objects. How do we do this?

let fridge = [
  { fruit: '🍊', amount: 0 },
  { fruit: '🍎', amount: 1 },
  { fruit: '🍐', amount: 0 },
  { fruit: 'πŸ‰', amount: 1 },
  { fruit: '🍌', amount: 0 }
];

let shoppingList = fridge.filter(function (fruitObject) {
  if (fruitObject.amount === 0) {
    return true;
  } else {
    return false;
  }
});

After filtering the fridge array with the given callback function, we will have a new array (shoppingList variable) containing the following:

[
  { fruit: '🍊', amount: 0 },
  { fruit: '🍐', amount: 0 },
  { fruit: '🍌', amount: 0 }
];

As a bonus, now we can map through this new shoppingList array to do some groceries!

let shoppingList = [
  { fruit: '🍊', amount: 0 },
  { fruit: '🍐', amount: 0 },
  { fruit: '🍌', amount: 0 }
];

let shoppingBasket = shoppingList.map((fruitObject) => ({
  ...fruitObject,
  amount: 5
}));

Now we have a shopping basket full of fresh and juicy fruit! πŸ˜‹

reduce array values to a single value

With the reduce(function(accumulator, value, index), initialValue) method from the Array object we can iterate over the elements and return a single value. The second argument of the reduce function is initialValue, which will be used as the initial value for the accumulator. If you don't pass anything as this argument it will use the first value of the array and it will be skipped. My recommendation is to always pass something to this argument just to be more clear about what are you expecting to obtain at the end, plus if you use TypeScript you will get very nice intellisense about it πŸ™ƒ

Let's imagine once again that we have a fridge full of fruits shaped as a javascript object like the following:

let fruitObject = {
  fruit: '🍎',
  amount: 1
};

And now we would like to check how many fruit we have stored in the fridge in total. How do we do this?

let fridge = [
  { fruit: '🍊', amount: 2 },
  { fruit: '🍎', amount: 4 },
  { fruit: '🍐', amount: 1 },
  { fruit: 'πŸ‰', amount: 0 },
  { fruit: '🍌', amount: 3 }
];

let amountOfFruits = fridge.reduce(function (accumulated, fruitObject) {
  return accumulated + fruitObject.amount;
}, 0);

amountOfFruits; // 2 + 4 + 1 + 0 + 3 = 10

The reduce method is a very handy function when you'd like to operate with arrays to obtain some value from them but you always have to remember that this function is very computational expensive so, if you can, you should try to avoid it if your CPU budget is low or you want to keep your application performing as best as possible. As a more performant alternative you can for example, use a for loop like the following because it's worth it πŸ‘ŒπŸ»

let fridge = [
  { fruit: '🍊', amount: 2 },
  { fruit: '🍎', amount: 4 },
  { fruit: '🍐', amount: 1 },
  { fruit: 'πŸ‰', amount: 0 },
  { fruit: '🍌', amount: 3 }
];

let amountOfFruits = 0;
let fruitsOnTheFridge = fridge.length;

for (let index = 0; index <= fruitsOnTheFridge; index++) {
  amountOfFruits += fridge[index].amount;
}

amountOfFruits; // 2 + 4 + 1 + 0 + 3 = 10

Iterating over an array with a for of loop

Another way for iterating over an array is with a for of loop, this is a very simple and readable loop type.

Let's iterate over the fruits on the fridge!

let fridge = [
  { fruit: '🍊', amount: 2 },
  { fruit: '🍎', amount: 4 },
  { fruit: '🍐', amount: 1 },
  { fruit: 'πŸ‰', amount: 0 },
  { fruit: '🍌', amount: 3 }
];

for (let fruit of fridge) {
  console.log(fruit);
}

// {fruit: "🍊", amount: 2}
// {fruit: "🍎", amount: 4}
// {fruit: "🍐", amount: 1}
// {fruit: "πŸ‰", amount: 0}
// {fruit: "🍌", amount: 3}

As you can see from the code snippet above, this is a much more simpler way to iterate over an array. For each of the iterations, it stores the value of the current index element on the fruit variable and you can use it to manipulate it as you please.

Creating an array from

With the from(arrayLikeObject, mapFunction) method from the Array object we can create a new Array from an iterable object.

let fruitsString = 'πŸŠπŸŽπŸπŸ‰πŸŒ';
let fruits = Array.from(fruitsString);

fruits; // ['🍊', '🍎', '🍐', 'πŸ‰', '🍌']

In the example above we've used a string, in JavaScript a string is an array-like object because it has a length property, but any object that has a length property or indexed elements can be used as well. Also the Map and Set objects can be used here because they are iterables, an therefore, perfectly valid.

The second argument of the from method is a callback function used to iterate over the elements after they're created, meaning that we can, for example apply some logic to each of them, like the following:

let fruitsString = 'πŸŠπŸŽπŸπŸ‰πŸŒ';
let fruits = Array.from(fruitsString, function (element) {
  return {
    fruit: element,
    amount: 5
  };
});

// {fruit: "🍊", amount: 5}
// {fruit: "🍎", amount: 5}
// {fruit: "🍐", amount: 5}
// {fruit: "πŸ‰", amount: 5}
// {fruit: "🍌", amount: 5}

As we can see by the code snippet above, this method is very flexible and powerful and we've created an array of objects with some custom properties as we wanted.

##Β Joining elements from an array into a string

With the join(separator) method from the Array object we can join the elements of an array into a string.

let fruits = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];
let fruitsString = fruits.join();

fruitsString; // "🍊,🍎,🍐,πŸ‰,🍌"

As we can tell by the code snippet above, the join method behaves a little weirdly when no separator argument is provided, this is because if we don't provide anything, it will use a , (coma) to separate the elements. If you would like to, for instance, have them all together, you could tell the join method to use an empty string '' as the separator.

let fruits = ['🍊', '🍎', '🍐', 'πŸ‰', '🍌'];
let fruitsString = fruits.join('');

fruitsString; // "πŸŠπŸŽπŸπŸ‰πŸŒ"

Checking if a value is an Array.

With the isArray(object) method from the Array object we can determine if the object passed as the main an only argument is an Array. This method will return true or false depending if the object meets the requirements or not.

Lets see how this actually behaves in different positive (true) scenarios:

Array.isArray([]); // true
Array.isArray(['🍎']); // true
Array.isArray(new Array()); // true
Array.isArray(new Array('🍎', '🍐', '🍊')); // true
Array.isArray(new Array(4)); // true
Array.isArray(Array.prototype); // true

Now lets see how this actually behaves in different negative (false) scenarios:

Array.isArray(); // false
Array.isArray({}); // false
Array.isArray(undefined); // false
Array.isArray(null); // false
Array.isArray(4); // false
Array.isArray('OTPfy'); // false
Array.isArray(true); // false
Array.isArray(false); // false

Flattening arrays

With the flat(depth) method from the Array object we can flatten an array that contains more arrays (sub-arrays) as values.

Lets imagine that our fridge contains different bags which fruit is contained on each of those bags and we would like to extract all the fruit from those bags to later on do something with that fruit. How do we do this?

let fridge = [
  ['🍎', '🍎', '🍎', '🍎'], // apples bag
  ['🍐', '🍐'], // pears bag
  ['🍊'] // oranges bag
];

let allFruits = fridge.flat();

allFruits; // ["🍎", "🍎", "🍎", "🍎", "🍐", "🍐", "🍊"]

As we can see by the code snippet above, the flat method comes to be very handy when we want to obtain a single array without any nesting. Let's take a look at a more complex example:

let fridge = [
  ['🍎', '🍎', '🍎', '🍎'], // apples bag
  ['🍐', ['🍐', '🍐']], // pears bag
  [['🍊', ['🍊']], '🍊'] // oranges bag
];

let allFruits = fridge.flat();

allFruits; // ["🍎", "🍎", "🍎", "🍎", "🍐", ["🍐", "🍐"], ["🍊", ["🍊"]], "🍊"]

By looking at the output of the above code snippet we can determine that if we don't pass any numeric value to the depth argument of the flat method, it will only perform a flatten operation on the first-level row of array elements.

Let's now take a look at what happens if we pass a value to the depth property.

let fridge = [
  ['🍎', '🍎', '🍎', '🍎'], // apples bag
  ['🍐', ['🍐', '🍐']], // pears bag
  [['🍊', ['🍊']], '🍊'] // oranges bag
];

let allFruits = fridge.flat(2);

allFruits; // ["🍎", "🍎", "🍎", "🍎", "🍐", "🍐", "🍐", "🍊", ["🍊"], "🍊"]

As we can see by the output, by passing 2 as the depth property it flattens the array also on the second-level row of array elements but, our array is a three-level deep array. Let's flatten this by a depth of three an see what happens.

let fridge = [
  ['🍎', '🍎', '🍎', '🍎'], // apples bag
  ['🍐', ['🍐', '🍐']], // pears bag
  [['🍊', ['🍊']], '🍊'] // oranges bag
];

let allFruits = fridge.flat(2);

allFruits; // ["🍎", "🍎", "🍎", "🍎", "🍐", "🍐", "🍐", "🍊", "🍊", "🍊"]

Great, we've achieved our objective of completely flattening the array into a single depth array!