Spread Operator: How Spread Works in JavaScript
Tags: javascript, programming, webdev, coding
Published: 2021-08-27 23:16:16

The **spread operator** (`...`) is a syntax that helps to expand iterables into individual elements.

The spread syntax serves within *array literals*, *function calls*, and *initialized properties object* to spread the values of [iterable objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#Iterables) into separate items.

> **Note**
>
> A spread syntax is effective only when used within array literals, function calls, or initialized properties objects.

So, what exactly does this mean? Let’s see with some examples.

## Spread Example 1: How spread works in an array literal

```js
const myName = ["Sofela", "is", "my"];
const aboutMe = ["Oluwatobi", ...myName, "name."];

console.log(aboutMe);

// The invocation above will return:
[ "Oluwatobi", "Sofela", "is", "my", "name." ]
```

**[Try it on StackBlitz](https://stackblitz.com/edit/web-platform-rd1npd?file=script.js)**

The snippet above used spread (`...`) to copy `myName` array into `aboutMe`.

> **Note**
>
> * Alterations to `myName` will not reflect in `aboutMe` because all the values inside `myName` are [primitives](https://www.codesweetly.com/web-tech-glossary#primitive-data-js). Therefore, the spread operator simply copied and pasted `myName`’s content into `aboutMe` without creating any reference back to the original array.
>
> * As mentioned by @nombrekeff in the comment section, the spread operator *only* does shallow copy. So, keep in mind that supposing `myName` contained any [non-primitive](https://www.codesweetly.com/web-tech-glossary#non-primitive-data-js) value, the computer would have created a reference between `myName` and `aboutMe`. See [info 3](#info-3-beware-of-how-spread-works-when-used-on-objects-containing-nonprimitives) for more on how the spread operator works with primitive and non-primitive values.
>
> * Suppose we did not use the spread syntax to duplicate `myName`’s content. For instance, if we had written `const aboutMe = ["Oluwatobi", myName, "name."]`. In such a case, the computer would have assigned a reference back to `myName`. As such, any change made in the original array would reflect in the duplicated one.

## Spread Example 2: How to use spread to convert a string into individual array items

```js
const myName = "Oluwatobi Sofela";

console.log([...myName]);

// The invocation above will return:
[ "O", "l", "u", "w", "a", "t", "o", "b", "i", " ", "S", "o", "f", "e", "l", "a" ]
```

**[Try it on StackBlitz](https://stackblitz.com/edit/web-platform-axvtye?file=script.js)**

In the snippet above, we used the spread syntax (`...`) within an array literal object (`[...]`) to expand `myName`’s string value into individual items.

As such, `"Oluwatobi Sofela"` got expanded into `[ "O", "l", "u", "w", "a", "t", "o", "b", "i", " ", "S", "o", "f", "e", "l", "a" ]`.

## Spread Example 3: How the spread operator works in a function call

```js
const numbers = [1, 3, 5, 7];

function addNumbers(a, b, c, d) {
  return a + b + c + d;
}

console.log(addNumbers(...numbers));

// The invocation above will return:
16
```

**[Try it on StackBlitz](https://stackblitz.com/edit/web-platform-nrn8f3?file=script.js)**

In the snippet above, we used the spread syntax to spread the `numbers` array’s content across `addNumbers()`’s parameters.

Suppose the `numbers` array had more than four items. In such a case, the computer will only use the first four items as `addNumbers()` argument and ignore the rest.

**Here’s an example:**

```js
const numbers = [1, 3, 5, 7, 10, 200, 90, 59];

function addNumbers(a, b, c, d) {
  return a + b + c + d;
}

console.log(addNumbers(...numbers));

// The invocation above will return:
16
```

**[Try it on StackBlitz](https://stackblitz.com/edit/web-platform-ef3ncm?file=script.js)**

**Here’s another example:**

```js
const myName = "Oluwatobi Sofela";

function spellName(a, b, c) {
  return a + b + c;
}

console.log(spellName(...myName));      // returns: "Olu"
console.log(spellName(...myName[3]));   // returns: "wundefinedundefined"
console.log(spellName([...myName]));    // returns: "O,l,u,w,a,t,o,b,i, ,S,o,f,e,l,aundefinedundefined"
console.log(spellName({...myName}));    // returns: "[object Object]undefinedundefined"
```

**[Try it on StackBlitz](https://stackblitz.com/edit/web-platform-pkrxjd?file=script.js)**

## Spread Example 4: How spread works in an object literal

```js
const myNames = ["Oluwatobi", "Sofela"];
const bio = { ...myNames, runs: "codesweetly.com" };

console.log(bio);

// The invocation above will return:
{ 0: "Oluwatobi", 1: "Sofela", runs: "codesweetly.com" }
```

**[Try it on StackBlitz](https://stackblitz.com/edit/web-platform-qnmxsu?file=script.js)**

In the snippet above, we used spread inside the `bio` object to expand `myNames` values into individual properties.

## Important stuff to know about the spread operator

Keep these two essential pieces of info in mind whenever you choose to use the spread operator.

### Info 1: Spread operators can’t expand object literal’s values

Since a properties object is not an [iterable object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#Iterables), you cannot use the spread syntax to expand its values.

However, you can use the *spread operator* to clone *properties* from one object into another.

**Here’s an example:**

```js
const myName = { firstName: "Oluwatobi", lastName: "Sofela" };
const bio = { ...myName, website: "codesweetly.com" };

console.log(bio);

// The invocation above will return:
{ firstName: "Oluwatobi", lastName: "Sofela", website: "codesweetly.com" };
```

**[Try it on StackBlitz](https://stackblitz.com/edit/web-platform-psnsa8?file=script.js)**

The snippet above used the spread operator to clone `myName`’s content into the `bio` object.

> **Note**
>
> * The spread operator can expand *iterable objects*’ values only.
>
> * An object is iterable only if it (or any object in its prototype chain) has a property with a [@@iterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterable_protocol) key.
>
> * [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/@@iterator), [TypedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/@@iterator), [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/@@iterator), [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/@@iterator), and [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/@@iterator) are all built-in iterable types because they have the `@@iterator` property by default.
>
> * A properties object is not an iterable [data](https://www.codesweetly.com/document-vs-data-vs-code) type because it does not have the `@@iterator` property by default.
>
> * You can [make a properties object iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator#user-defined_iterables) by adding `@@iterator` onto it.

### Info 2: The spread operator does not clone identical properties

Suppose you used the spread operator to clone properties from object A into object B. And suppose object B contains properties identical to those in object A. In such a case, B’s versions will override those inside A.

**Here’s an example:**

```js
const myName = { firstName: "Tobi", lastName: "Sofela" };
const bio = { ...myName, firstName: "Oluwatobi", website: "codesweetly.com" };

console.log(bio);

// The invocation above will return:
{ firstName: "Oluwatobi", lastName: "Sofela", website: "codesweetly.com" };
```

**[Try it on StackBlitz](https://stackblitz.com/edit/web-platform-gjhjue?file=script.js)**

Observe that the spread operator did not copy `myName`’s `firstName` property into the `bio` object because `bio` already contains a `firstName` property.

### Info 3: Beware of how spread works when used on objects containing non-primitives!

Suppose you used the spread operator on an object (or array) containing *only* [primitive values](https://www.codesweetly.com/web-tech-glossary#primitive-data-js). The computer *will not* create any reference between the original object and the duplicated one.

For instance, consider this code below:

```js
const myName = ["Sofela", "is", "my"];
const aboutMe = ["Oluwatobi", ...myName, "name."];

console.log(aboutMe);

// The invocation above will return:
["Oluwatobi", "Sofela", "is", "my", "name."]
```

**[Try it on StackBlitz](https://stackblitz.com/edit/web-platform-rd1npd?file=script.js)**

Observe that every item in `myName` is a primitive value. Therefore, when we used the spread operator to clone `myName` into `aboutMe`, the computer *did not* create any reference between the two arrays.

As such, any alteration you make to `myName` *will not* reflect in `aboutMe`, and vice versa.

Take for an example, let’s add more content to `myName`:

```js
myName.push("real");
```

Now, let’s check the current state of `myName` and `aboutMe`:

```js
console.log(myName); // ["Sofela", "is", "my", "real"]
console.log(aboutMe); // ["Oluwatobi", "Sofela", "is", "my", "name."]
```

**[Try it on StackBlitz](https://stackblitz.com/edit/web-platform-ujs6ny?file=script.js)**

Notice that `myName`’s updated content *did not* reflect in `aboutMe` — because spread created no reference between the original array and the duplicated one.

#### What if `myName` contains non-primitive items?

Suppose `myName` contained [non-primitives](https://www.codesweetly.com/web-tech-glossary#non-primitive-data-js). In that case, spread *will* create a reference between the original non-primitive and the cloned one.

**Here is an example:**

```js
const myName = [["Sofela", "is", "my"]];
const aboutMe = ["Oluwatobi", ...myName, "name."];

console.log(aboutMe);

// The invocation above will return:
[ "Oluwatobi", ["Sofela", "is", "my"], "name." ]
```

**[Try it on StackBlitz](https://stackblitz.com/edit/web-platform-ombp5w?file=script.js)**

Observe that `myName` contains a non-primitive value.

Therefore, using the spread operator to clone `myName`’s content into `aboutMe` caused the computer to create a reference between the two arrays.

As such, any alteration you make to `myName`’s copy will reflect in `aboutMe`’s version, and vice versa.

Take for an example, let’s add more content to `myName`:

```js
myName[0].push("real");
```

Now, let’s check the current state of `myName` and `aboutMe`:

```js
console.log(myName); // [["Sofela", "is", "my", "real"]]
console.log(aboutMe); // ["Oluwatobi", ["Sofela", "is", "my", "real"], "name."]
```

**[Try it on StackBlitz](https://stackblitz.com/edit/web-platform-qpyy8n?file=script.js)**

Notice that `myName`’s updated content is reflected in `aboutMe` — because spread created a reference between the original array and the duplicated one.

**Here’s another example:**

```js
const myName = { firstName: "Oluwatobi", lastName: "Sofela" };
const bio = { ...myName };

myName.firstName = "Tobi";

console.log(myName); // { firstName: "Tobi", lastName: "Sofela" }
console.log(bio); // { firstName: "Oluwatobi", lastName: "Sofela" }
```

**[Try it on StackBlitz](https://stackblitz.com/edit/web-platform-tbmtgm?file=script.js)**

In the snippet above, `myName`’s update *did not* reflect in `bio` because we used the spread operator on an object that contains primitive values *only*.

> **Note**
>
> A developer would call `myName` a **shallow object** because it contains only primitive items.

**Here’s one more example:**

```js
const myName = { 
  fullName: { firstName: "Oluwatobi", lastName: "Sofela" }
};

const bio = { ...myName };

myName.fullName.firstName = "Tobi";

console.log(myName); // { fullName: { firstName: "Tobi", lastName: "Sofela" } }
console.log(bio); // { fullName: { firstName: "Tobi", lastName: "Sofela" } }
```

**[Try it on StackBlitz](https://stackblitz.com/edit/web-platform-9uce9g?file=script.js)**

In the snippet above, `myName`’s update is reflected in `bio` because we used the spread operator on an object that contains a non-primitive value.

> **Note**
>
> * A developer would call `myName` a **deep object** because it contains a non-primitive item.
>
> * You do **shallow copy** when you create references while cloning one object into another. For instance, `...myName` produces a shallow copy of the `myName` object because whatever alteration you make in one will reflect in the other.
>
> * You do **deep copy** when you clone objects without creating references. For instance, I could deep copy `myName` into `bio` by doing `const bio = JSON.parse(JSON.stringify(myName))`. By so doing, the computer will clone `myName` into `bio` without creating any reference.
>
> * You can break off the reference between the two objects by replacing the `fullName` object inside `myName` or `bio` with a new object. For instance, doing `myName.fullName = { firstName: "Tobi", lastName: "Sofela" }` would disconnect the pointer between `myName` and `bio`.

## Wrapping it up

This article discussed what the spread operator is. We also looked at how spread works in array literals, function calls, and object literals.

Now that we know how spread works, let’s discuss the **rest** operator in [this article](https://www.codesweetly.com/javascript-rest-operator/) so we can see the differences.

Thanks for reading!