Skip to content
Announcing the new Pro Zone. Check it out!

Spread Operator – How Spread Works in JavaScript

The spread operator (...) helps you expand iterables into individual elements.

The spread syntax serves within array literals, function calls, and initialized properties objects to spread the values of iterable objects into separate items. So effectively, it does the opposite thing from the rest operator.

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

Spread Example 1: How Spread Works in an Array Literal

const myName = ["Sofela", "is", "my"];
const aboutMe = ["Oluwatobi", ...myName, "name."];
console.log(aboutMe);
// The invocation above will return:
// ["Oluwatobi", "Sofela", "is", "my", "name."]

Try Editing It

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

Spread Example 2: How to Use Spread to Convert a String into Individual Array Items

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 Editing It

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

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 Editing It

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:

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 Editing It

Here’s another example:

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 Editing It

Spread Example 4: How Spread Works in an Object Literal

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 Editing It

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

So now that we know what the spread operator is, we can talk about what makes it different from the rest operator.

Rest vs. Spread Operator: What’s the Difference?

JavaScript uses three dots (...) for both the rest and spread operators. But these two operators are not the same.

The main difference between rest and spread is that the rest operator puts the rest of some specific user-supplied values into a JavaScript array. But the spread syntax expands iterables into individual elements.

For instance, consider this code that uses rest to enclose some values into an array:

// Use rest to enclose the rest of specific user-supplied values into an array:
function myBio(firstName, lastName, ...otherInfo) {
return otherInfo;
}
// Invoke myBio function while passing five arguments to its parameters:
myBio("Oluwatobi", "Sofela", "CodeSweetly", "Web Developer", "Male");
// The invocation above will return:
// ["CodeSweetly", "Web Developer", "Male"]

Try Editing It

In the snippet above, we used the ...otherInfo rest parameter to encase "CodeSweetly", "Web Developer", and "Male" into an array.

Now, consider this example of a spread operator:

// Define a function with three parameters:
function myBio(firstName, lastName, company) {
return `${firstName} ${lastName} runs ${company}`;
}
// Use spread to expand an array's items into individual arguments:
myBio(...["Oluwatobi", "Sofela", "CodeSweetly"]);
// The invocation above will return: "Oluwatobi Sofela runs CodeSweetly"

Try Editing It

In the snippet above, we used the spread operator (...) to spread ["Oluwatobi", "Sofela", "CodeSweetly"]’s content across myBio()’s parameters.

Important Stuff to Know about the Spread Operator

Keep these four 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, you cannot use the spread operator to expand its values.

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

Here’s an example:

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 Editing It

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

Info 2: The spread operator does not clone identical properties

When using the spread operator, suppose you 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:

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 Editing It

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: How does spread work on objects containing only primitive values?

Suppose you used the spread operator on an object (or array) containing only primitive values. The computer will not create any reference between the original object and the duplicated one.

For instance, consider this code below:

const myName = ["Sofela", "is", "my"];
const aboutMe = ["Oluwatobi", ...myName, "name."];
console.log(aboutMe);
// The invocation above will return:
// ["Oluwatobi", "Sofela", "is", "my", "name."]

Try Editing It

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.

As an example, let’s add more content to myName:

myName.push("real");

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

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

Try Editing It

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

Info 4: How does spread work on objects containing one or more non-primitive values?

Suppose you used the spread operator on an object (or array) containing one or more non-primitives. In that case, spread will create a reference between the original non-primitive and the cloned one.

Here is an example:

const myName = [["Sofela", "is", "my"]];
const aboutMe = ["Oluwatobi", ...myName, "name."];
console.log(aboutMe);
// The invocation above will return:
// ["Oluwatobi", ["Sofela", "is", "my"], "name."]

Try Editing It

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.

As an example, let’s add more content to myName:

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

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

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

Try Editing It

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:

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 Editing It

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.

Here’s one more example:

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 Editing It

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.

Shallow Copy vs. Deep Copy: What’s the Difference?

You do shallow copy when you create references while cloning one object into another. For instance, consider this snippet:

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 Editing It

...myName produces a shallow copy of the myName object because whatever alteration you make in one will reflect in the other. In other words, bio’s detachment from myName is shallow since they still have some connections.

You do deep copy when you clone objects without creating references. The JSON.parse(JSON.stringify()) and structuredClone() methods are tools you can use to create a deep copy.

Here’s an example:

const myName = {
fullName: { firstName: "Oluwatobi", lastName: "Sofela" },
};
const bio = JSON.parse(JSON.stringify(myName));
myName.fullName.firstName = "Tobi";
console.log(myName); // { fullName: { firstName: "Tobi", lastName: "Sofela" } }
console.log(bio); // { fullName: { firstName: "Oluwatobi", lastName: "Sofela" } }

Try Editing It

The snippet above used the JSON.parse(JSON.stringify()) method to clone myName into bio without creating any reference (deep copy). In other words, bio’s detachment from myName is deep since they no longer have any connections.

Here’s another example:

const myName = {
fullName: { firstName: "Oluwatobi", lastName: "Sofela" },
};
const bio = structuredClone(myName);
myName.fullName.firstName = "Tobi";
console.log(myName); // { fullName: { firstName: "Tobi", lastName: "Sofela" } }
console.log(bio); // { fullName: { firstName: "Oluwatobi", lastName: "Sofela" } }

Try Editing It

The snippet above used the structuredClone() method to clone myName into bio without creating any reference (deep copy). In other words, bio’s detachment from myName is deep since they no longer have any connections.

You can break off the reference between two connected objects by replacing any of the two with a new object.

Here’s an example:

// Create a deep object:
const myName = {
fullName: { firstName: "Oluwatobi", lastName: "Sofela" },
};
// Create a shallow copy of myName:
const bio = { ...myName };
// Change myName's firstName:
myName.fullName.firstName = "Tobi";
// Check myName's content:
console.log(myName); // { fullName: { firstName: "Tobi", lastName: "Sofela" } }
// Check bio's content:
console.log(bio); // { fullName: { firstName: "Tobi", lastName: "Sofela" } }
// Notice that myName and bio are linked. Let's break the connection:
myName.fullName = { firstName: "Oluwa", lastName: "Sofela" };
// Check myName's content:
console.log(myName); // { fullName: { firstName: "Oluwa", lastName: "Sofela" } }
// Check bio's content:
console.log(bio); // { fullName: { firstName: "Tobi", lastName: "Sofela" } }

Try Editing It

The snippet above disconnected the pointer between myName and bio’s fullName objects by reassigning myName.fullName with a new object.