Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

The... Spread Operator

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

The second thing weird thing we need to talk about is much more important. It's called the spread operator. Open up play.js and clear everything out. Create a new function called printThreeThings(thing1, thing2, thing3). Inside, console.log() our three things:

8 lines play.js
let printThreeThings = function(thing1, thing2, thing3) {
console.log(thing1, thing2, thing3);
};
... lines 4 - 8

Easy enough!

Below that, create a new array called yummyThings, which of course naturally will include pizza, gelato, and sushi:

8 lines play.js
let printThreeThings = function(thing1, thing2, thing3) {
console.log(thing1, thing2, thing3);
};
let yummyThings = ['pizza', 'gelato', 'sushi'];
... lines 6 - 8

All delicious, but maybe not if you eat them all at the same time.

Here's the question:

How can I pass the three yummy things as the first, second, and third argument to printThreeThings()?

Well, we could say printThreeThings() with yummyThings[0], yummyThings[1] and yummyThings[2]. But! Not cool enough! In ES2015, you can use the spread operator: printThreeThings(...yummyThings):

8 lines play.js
let printThreeThings = function(thing1, thing2, thing3) {
console.log(thing1, thing2, thing3);
};
let yummyThings = ['pizza', 'gelato', 'sushi'];
printThreeThings(...yummyThings);

Woh.

If we try that, it prints our three things! That's crazy! The ... is called the "spread operator": it's always ... and then your array. When you do this, it's almost as if somebody went through and literally just wrote out all of the items in your array manually, instead of us doing it by hand.

But of course, there are a lot of yummy things in the world, and since I'm from the US, my yummyThings should probably have a cheeseburger:

8 lines play.js
let printThreeThings = function(thing1, thing2, thing3) {
console.log(thing1, thing2, thing3);
};
let yummyThings = ['pizza', 'gelato', 'sushi', 'cheeseburger'];
printThreeThings(...yummyThings);

What will happen now? The array has 4 things, but we only have 3 arguments? Let's find out! Run the script!

It's the same result! Thanks to the spread operator, pizza is passed as the first argument, then gelato, sushi and finally, cheeseburger is passed as the 4th argument. Since the function doesn't have a 4th argument, it's just ignored!

Spread Operator as an Array Merge

Ok great! But you're probably asking yourself: how could this ever be useful in any real world scenario?

Dang, good question. Actually, there are two really great use-cases. One is in ReactJS. I won't talk about it now... just trust me! The second deals with merging arrays together.

Suppose we need to create another array called greatThings. And we decide that swimming is super great, and sunsets are the best. They are the best. We also decide that anything "yummy" must also be great, so I want to add all four of these yummyThings into the greatThings array. In PHP, we might use array_merge(). In JavaScript, one option is the spread operator. Add a comma - as if we were going to add another entry - and then say ...yummyThings. We could even keep going and add something else great, like New Orleans. Because New Orleans is a really great place:

6 lines play.js
let yummyThings = ['pizza', 'gelato', 'sushi', 'cheeseburger'];
let greatThings = ['swimming', 'sunsets', ...yummyThings, 'New Orleans'];
... lines 4 - 6

Tip

There are often many ways to do the same thing in JavaScript, especially with arrays and objects. In this case, greatThings.concat(yummyThings) is also an option.

Ok, console.log(greatThings) to see if it works!

6 lines play.js
let yummyThings = ['pizza', 'gelato', 'sushi', 'cheeseburger'];
let greatThings = ['swimming', 'sunsets', ...yummyThings, 'New Orleans'];
console.log(greatThings);

It does: swimming, sunset, 4 yummy things, and New Orleans at the bottom.

Spread Operator for Creating a new Array

But the spread operator has one more cool trick. At the bottom, add another variable: let copyOfGreatThings = greatThings:

10 lines play.js
let yummyThings = ['pizza', 'gelato', 'sushi', 'cheeseburger'];
let greatThings = ['swimming', 'sunsets', ...yummyThings, 'New Orleans'];
let copyOfGreatThings = greatThings;
... lines 6 - 10

Now, add something else to this new variable: use copyOfGreatThings.push() to add something that we all know is great: summer:

10 lines play.js
let yummyThings = ['pizza', 'gelato', 'sushi', 'cheeseburger'];
let greatThings = ['swimming', 'sunsets', ...yummyThings, 'New Orleans'];
let copyOfGreatThings = greatThings;
copyOfGreatThings.push('summer');
... lines 7 - 10

At the bottom, console.log(copyOfGreatThings):

10 lines play.js
let yummyThings = ['pizza', 'gelato', 'sushi', 'cheeseburger'];
let greatThings = ['swimming', 'sunsets', ...yummyThings, 'New Orleans'];
let copyOfGreatThings = greatThings;
copyOfGreatThings.push('summer');
console.log(greatThings);
console.log(copyOfGreatThings);

Here's the question: we know summer now lives in copyOfGreatThings(). But does it also now live inside of greatThings? Try it! It does! Summer lives in both arrays! And this makes sense: arrays are objects in JavaScript, and just like in PHP, objects are passed by reference. In reality, greatThings and copyOfGreatThings are identical: they both point to the same array in memory.

As we get more advanced, especially in React.js, the idea of not mutating objects will become increasingly important. What I mean is, there will be times when it wil be really important to copy an object, instead of modifying the original.

So how could we make copyOfGreatThings a true copy? The spread operator has an answer: re-assign copyOfGreatThings to [...greatThings]:

10 lines play.js
let yummyThings = ['pizza', 'gelato', 'sushi', 'cheeseburger'];
let greatThings = ['swimming', 'sunsets', ...yummyThings, 'New Orleans'];
let copyOfGreatThings = [...greatThings];
... lines 6 - 10

And that is it! This will create a new array, and then put each item from greatThings into it, one-by-one.

Try it! Yes! We can see summer in the copy, but we did not modify the original array.

Ok, let's move on something that's instantly useful: template strings!

Leave a comment!

0
Login or Register to join the conversation
Cat in space

"Houston: no signs of life"
Start the conversation!

This tutorial uses Symfony 3. But, since this is a JavaScript tutorial, all the concepts work fine in newer versions of Symfony.

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.2.0",
        "symfony/symfony": "3.2.*", // v3.2.14
        "twig/twig": "2.10.*", // v2.10.0
        "doctrine/orm": "^2.5", // v2.7.1
        "doctrine/doctrine-bundle": "^1.6", // 1.10.3
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.2
        "symfony/swiftmailer-bundle": "^2.3", // v2.4.2
        "symfony/monolog-bundle": "^2.8", // v2.12.1
        "symfony/polyfill-apcu": "^1.0", // v1.3.0
        "sensio/distribution-bundle": "^5.0", // v5.0.22
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.19
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "friendsofsymfony/user-bundle": "~2.0@dev", // dev-master
        "doctrine/doctrine-fixtures-bundle": "~2.3", // v2.4.1
        "doctrine/doctrine-migrations-bundle": "^1.2", // v1.2.1
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "friendsofsymfony/jsrouting-bundle": "^1.6" // 1.6.0
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.1.2
        "symfony/phpunit-bridge": "^3.0" // v3.2.2
    }
}
userVoice