const - JS | lectureData Structures, Modern Operators & Strings

The Spread Operator (...)

Data Structures, Modern Operators & Strings

We can use the spread operator to expand an array into all its elements. So basically, unpacking all the array elements at once.

Consider the below array:

script.js
const arr = [1, 7, 9];

Now let's say we want to create a new array based on the above array but with some new elements at the beginning. How would we do that? Well, with what we already know, we would need to loop over this array, or even worse, do it manually, for example, like this.

script.js
const newArray = [4, 6, 2, arr[0], arr[1], arr[2]];

Spread Operator - 1

You can see that we get a new array with the three original elements and then 4, 6, and 2 at the beginning of the array. This is actually quite a common operation that we need to do, and so we can now, since ES6, do it in a much better way using the spread operator.

With the spread operator, it's going to work like this.

script.js
/**
 * The three dots (...arr) expands the array into all of it's
 * individual elements
 */

const newArray = [4, 6, 2, ...arr];
console.log(newArray);

Spread Operator - 4

You see that we get the same result. So what the spread operator does is to take all the values out of the array, arr, and then write them individually as if we wrote 1, 7, and 9 manually.

If we wrote it without those three dots, we would have this:

Spread Operator - 5

That's because we are including this entire array arr. But with the spread operator, again, it's like taking all the elements out of the array and writing them manually.

What this means is that we can use the spread operator whenever we would otherwise write multiple values separated by commas. And that situation happens whenever we write an array literal. That's the first situation in which expanding an array is very useful.

The second situation is when we pass arguments into functions. For example, let's say that we wanted to log the individual elements of the array newArr.

If we just logged the array, it's, of course, going to look like this.

script.js
const newArray = [4, 6, 2, ...arr];
console.log(newArray);

Spread Operator - 6

It's just one value with just the array. But if we use the spread operator to expand the array, this is what happens then.

script.js
const newArray = [4, 6, 2, ...arr];
console.log(...newArray);

Spread Operator - 7

Now it logged the individual elements of the array. So this would be the same as doing this:

script.js
console.log(4, 6, 2, 1, 7, 9);

Once again, whenever we need the elements of an array individually, then we can use the spread operator. And that is useful when we write an array and when we need to pass multiple elements into a function.

Let's see a bit more useful example. In this example, we will create an array with one more food item in the main menu array.

script.js
/**
 * We are writing a new array based on expanding the array
 * restaurant.mainMenu and adding another element (Gnocci) to it.
 */

const newMenu = [...restaurant.mainMenu, 'Gnocci'];
console.log(newMenu);

Spread Operator - 8

We can see that it has the three original elements, plus the Gnocci. And keep in mind that, we are indeed creating a completely new array. We are, of course, not manipulating the restaurant.mainMenu array. We are building a new array from scratch, and you can see that by the square brackets syntax.

Now you might have noticed that the spread operator is actually a bit similar to destructuring, because it also helps us get elements out of arrays. The big difference is that the spread operator takes all the elements from the array and it also doesn't create new variables.

As a consequence, we can only use it in places where we would otherwise write values separated by commas.

Next, let's learn about two important use cases of the spread operator, which is to create shallow copies of arrays, and to merge two arrays together.

Let's say we want to create a copy of the main menu.

script.js
const mainMenuCOpy = [...restaurant.mainMenu];

Doing this creates a shallow copy of this main menu array. That's a little bit similar to Object.assign that we used in a previous lecture. But here, this syntax is a lot easier to use.

Now to join two arrays together, i.e., join two arrays or more, of course, we can use the same technique. Maybe, at this point, you can already guess how that would work, and so you can do this, actually, as a challenge.

Just stop scrolling and create a variable called menu which will be an array that contains the whole menu. That is, both the main menu and the starter menu.

Guessing Time

Hopefully, you managed to do that. The secret here, again, is to use the spread operator.

script.js
const menu = [...restaurant.mainMenu, ...restaurant.starterMenu];
console.log(menu);

Spread Operator - 9

You can see that we now end up with an array containing all the food items that are both in the starter and the main menu. And again, because, with this spread operator, we took all the elements out of the starter menu and basically wrote them here into the new array (menu), and then the same with the main menu.

I told you that the spread operator works on arrays, but that's not entirely true because actually, the spread operator works on all so-called iterables. Now, the question is, what is an iterable?

There are different iterables in JavaScript. We will talk about all of them by the end of the course, but for now, just know that iterables are things like all arrays, strings, maps, or sets, but not objects. So basically, most of the built-in data structures in JavaScript are now iterables, but except objects.

Now, since strings are also iterables, that means that we can use the spread operator on a string, as well. Let me show that to you.

Let's start by creating a variable that holds the string 'Michael'

script.js
const str = 'Michael';

Then let's create an array containing all the individual letters and some other elements.

script.js
const letters = [...str, ' ', 'Sr.'];
console.log(letters);

Spread Operator - 10

You can see that we get an array, where each letter of the original string is now an individual element. Just like we unpacked an array, we now did the same thing with a string.

Keep in mind that we can still only use the spread operator when building an array, or when we pass values into a function. So for example, we can also do this.

script.js
console.log(...str);

// Which is the same thing as doing...

console.log('M', 'i', 'c', 'h', 'a', 'e', 'l');

Spread Operator - 11

What we can't do is to use the spread operator to build a string using a template literal. This is not going to work:

script.js
console.log(`${...str} Jordan`);

Spread Operator - 12

That's because it is not a place expecting multiple values separated by a comma; reason why we get unexpected token. Again, multiple values separated by a comma are usually only expected when we pass arguments into a function, or when we build a new array. Take note of that, because that is important to understand about the spread operator.

Enough with building arrays. Let's now actually write our own function that accepts multiple arguments and then use the spread operator to actually pass those arguments. That's going to be a real-life example .

Let's add another method to our restaurant object to order just pasta. And let's say the pasta always needs to have exactly three ingredients.

script.js
const restaurant = {
  // OTHER PROPERTIES AND METHODS

  orderPasta: function (ing_1, ing_2, ing_3) {
    console.log(
      `Here is your delicious pasta with ${ing_1}, ${ing_2} and ${ing_3}`
    );
  },
};

Before we call that method, I want to get these ingredients from a prompt window.

script.js
const ingredients = [
  prompt(`
  Let's eat some Pasta

  What's your first ingredient ?
  `),

  prompt(`What's your second ingredient ?`),
  prompt(`What's your third ingredient ?`),
];

console.log(ingredients);

Spread Operator - 13

Spread Operator - 16

Just to show you that it works, we can see that we now get an array of ingredients with A, B, and C, which are the three strings that I entered (You can try it by yourself).

Let's now actually call our orderPasta method. In the old way, we will write something like this:

script.js
restaurant.orderPasta(ingredients[0], ingredients[1], ingredients[2]);

But, since we learned about the spread operator in this lecture, we can now do a lot better. And so, instead, we do this.

script.js
restaurant.orderPasta(...ingredients);

Spread Operator - 17

You can see that we get the same result twice. What do you think is the better solution? And especially considering that an array could be a lot longer than just three elements. So indeed, always go with the modern ES6 spread operator syntax. It's an amazing addition to the language.

To finish this lecture here, since ES 2018, the spread operator actually also works on objects, even though objects are not iterables.

The first example that we did in this lecture was to create a new array based on one initial array. Let's now also create a new restaurant object with all the data from the original one plus some additional data.

It's actually amazing and much easier than with old JavaScript!

script.js
const newRestaurant = {
  ...restaurant,
  founder: 'Denny Imbroisi',
};

Here, the order does not matter as always. The spread operator doesn't have to be the first one. That is, let's say we also want the founding year,

script.js
const newRestaurant = {
  foundedIn: 2005,
  ...restaurant,
  founder: 'Denny Imbroisi',
};
console.log(newRestaurant);

Spread Operator - 18

With this, we created a brand new object. Hence, we get our original object, plus the founder, and plus founded in.

Finally, since we were able to do shallow copies of arrays, using the spread operator, we can do the same with objects. So instead of using Object.assign, as we did it in the previous lecture.

So let's do that.

script.js
const restaurantCopy = { ...restaurant };

And so now, if we attempt to change something on the copy,

script.js
restaurantCopy.name = 'Orties';

If we take a look at both of them, .i.e., the name of the copy and the original,

console.log(restaurant);
console.log(restaurantCopy);

Spread Operator - 19

You now see that they are different. The copy has the name of Orties, and the old one has Epoca, which means that, indeed, we did make a copy of the original restaurant. Because otherwise, as we learned by the end of the previous section, changing one object would then also change the other one.