The spread operator (the three dots of JavaScript) and its uses
Last updated: February 9, 2022.
You may have noticed the appearance of three little dots (...
) in some JavaScript code and what it means. This is the spread operator and is used for ‘spreading’ the individual elements of an iterable:
const myArray = [4, 6, 3, 5, 3, 5]; console.log(myArray); // Prints the array object: // [4,6,3,5,3,5] console.log(...myArray); // Prints the individual elements of the array: // 4 6 3 5 3 5
This may not seem like such a big deal, but there are a whole load of use cases where these three little dots prove extremely useful.
In this article, we walk you through the various use cases for the spread operator.
Table of contents
- 1 Uses of the spread operator
- 1.1 Copy a simple array
- 1.2 Merge arrays
- 1.3 With Math.min() and Math.max()
- 1.4 Create a function with an unknown number of arguments
- 1.5 List the characters of a string
- 1.6 Get non-destructured elements in array and object destructuring
- 1.7 Shallow copy an object
- 1.8 Merge objects
- Summary
Uses of the spread operator
#1: Copy a simple array
By spreading the individual elements of an array into a new array, the spread operator provides a fast and clean way to make an array copy:
const myArray = [4, 6, 3, 5, 3, 5]; const arrayCopy = [...myArray]; console.log(arrayCopy) // [4, 6, 3, 5, 3, 5]
You might intuitively think that there is a simpler way to do this: set the value of arrayCopy
to myArray
. But in JavaScript, this only creates a reference to the original array. Thus, if the copy is edited, the original is also edited:
const myArray = [4, 6, 3, 5, 3, 5]; const arrayCopy = myArray; arrayCopy[0] = "πΆ"; console.log(arrayCopy); // βοΈ // ["πΆ",6,3,5,3,5] console.log(myArray); // π± // ["πΆ",6,3,5,3,5]
The behavior in the above code is almost always unwanted. The spread operator helps us to make a better array copy:
const myArray = [4, 6, 3, 5, 3, 5]; const arrayCopy = [...myArray]; arrayCopy[0] = "πΆ"; console.log(arrayCopy); // βοΈ // ["πΆ",6,3,5,3,5] console.log(myArray); // βοΈ // [4,6,3,5,3,5]
But if your array contains nested properties, the referencing problem emerges for the nested properties even when using the spread operator:
const myArray = [4, 6, 3, 5, [3, 5]]; const arrayCopy = [...myArray]; arrayCopy[4][1] = "πΆ"; console.log(arrayCopy); // βοΈ // ["πΆ",6,3,5,3,5] console.log(myArray); // π± // ["πΆ",6,3,5,3,5]
To make a copy of an array that contains nesting, we recommend using the .cloneDeep
method from the third-party Lodash library.
The following code works if Lodash is already loaded from a CDN:
// Lodash already loaded in earlier script tag const myArray = [4, 6, 3, 5, [3, 5]]; const arrayCopy = _.cloneDeep(myArray); arrayCopy[4][1] = "πΆ"; console.log(arrayCopy); // βοΈ // [4, 6, 3, 5, [3, "πΆ"]] console.log(myArray); // βοΈ // [4, 6, 3, 5, [3, 5]]
#2: Merge arrays
Existing arrays can be merged into a new one by spreading their individual elements into a new array:
const dogArray = ["πΆ", "πΆ", "πΆ"]; const catArray = ["π±", "π±", "π±"]; const animalArray = [...dogArray, ...catArray]; console.log(animalArray); // ["πΆ","πΆ","πΆ","π±","π±","π±"]
The spread operator can also be used in combination with normally specified array elements:
const catArray = ["π±", "π±", "π±"]; const catArray2 = [...catArray, "Kitty", "Cat", "Meow"]; console.log(catArray2); // ["π±","π±","π±","Kitty","Cat","Meow"]
For completeness, here's what would happen if we didn't use the spread operator in the first example:
const dogArray = ["πΆ", "πΆ", "πΆ"]; const catArray = ["π±", "π±", "π±"]; const animalArray = [dogArray, catArray]; console.log(animalArray); // [["πΆ","πΆ","πΆ"],["π±","π±","π±"]]
We end up with an array containing two array objects: dogArray
and catArray
.
#3: With Math.min() and Math.max()
The .min()
and .max()
methods available on the Math
object accept a list of numbers and returns the lowest or largest number from the list. Try passing in an array object and NaN
will be returned because although it contains a list of numbers, it is itself an object.
The spread operator provides a simple way to get around this problem by spreading array values into Math.min()
and Math.max()
:
const myNumberArray = [5,2,7,4,4,2,7,8,2,3,5]; const minValue = Math.min(...myNumberArray); // Is the same as: Math.min(5,2,7,4,4,2,7,8,2,3,5) const maxValue = Math.max(...myNumberArray); // Is the same as: Math.max(5,2,7,4,4,2,7,8,2,3,5) console.log(minValue); // 2 console.log(maxValue); // 8
And here's the wrong way to do it:
// β Math.min or Math.max do not work if an array object is passed in: const myNumberArray = [5,2,7,4,4,2,7,8,2,3,5]; const minValue = Math.min(myNumberArray); const maxValue = Math.max(myNumberArray); console.log(minValue); // NaN console.log(maxValue); // NaN
#4: Create a function with an unknown number of arguments
A function accepts parameters as a comma-separated list.
By using the spread operator, we can create a function with an unspecified number of arguments passed in when called:
function(...args) { // function statement }
When is this useful? For example, when we want to join a list of string values together inside a function, but are unsure how many will be passed in each time:
function printFullName (...args) { const fullName = args.join(' '); console.log(fullName); } printFullName("Kiefer", "William", "Frederick", "Dempsey", "George", "Rufus", "Sutherland"); // "Kiefer William Frederick Dempsey George Rufus Sutherland" printFullName("BeyoncΓ©"); // "BeyoncΓ©"
#5: List characters of a string
Just as the spread operator can be used to list array elements, it can also list the characters of a string individually:
const name = "Britney"; console.log(...name); // "B" "r" "i" "t" "n" "e" "y"
#6: Get non-destructured elements in array and object destructuring
When destructuring an array or object, specifying ...rest
saves non-destructured elements to a new array or object called rest.
For example, here rest
becomes all elements apart from the destructured "Batman"
:
const superheroes = ["π¦", "πΈοΈ", "π§²"]; const [hero1, ...rest] = superheroes; console.log(hero1); // "π¦" console.log(rest); // ["πΈοΈ", "π§²"];
And in object destructuring, it works in the same way: a new object is produced, containing in the below example the non-destructured thumbnail and story properties:
const newsStory = { title: "Spiderman: Terrorist or hero?", category: "πΈοΈ", printTitle: function() { "The title of this article is "+this.title; } } const { title, ...rest } = newsStory; console.log(title); "Spiderman: Terrorist or hero?" console.log(rest); // { // category: "πΈοΈ", // printTitle: function() { // "The title of this article is "+this.title; // } // }
For more, you may want to check out our full tutorial on object and array destructuring.
#7: Shallow copy an object
In the ES2018 update to JavaScript, the use of the spread operator was extended to objects.
This allows copying an object by spreading the contents of an object into a new one:
const newsStory = { title: "Spiderman: Terrorist or hero?", category: "πΈοΈ", printTitle: function() { "The title of this article is "+this.title; } } const dataCopy = {...newsStory}; dataCopy.category = "π°" console.log(dataCopy); βοΈ // { // title: "Spiderman: Terrorist or hero?", // category: "π°", // printTitle: function() { // "The title of this article is "+this.title; // } // } console.log(newsStory); βοΈ // { // title: "Spiderman: Terrorist or hero?", // category: "πΈοΈ", // printTitle: function() { // "The title of this article is "+this.title; // } // }
This works perfectly well for copying non-nested properties, including those that contain methods.
But any nested properties in the copy are only references to the original object.
This means that if nested properties in the copy are changed, so too is the original object:
const newsStory = { title: "Spiderman: Terrorist or hero?", category: "πΈοΈ", attributes: { author: "Mary Jane Watson", importance: "π΄", } } const dataCopy = {...newsStory}; dataCopy.attributes.importance = "π‘"; console.log(dataCopy); βοΈ // { // title: "Spiderman: Terrorist or hero?", // category: "πΈοΈ", // attributes: { // author: "Mary Jane Watson", // importance: "π‘", // } // } console.log(newsStory); π¨ // { // title: "Spiderman: Terrorist or hero?", // category: "πΈοΈ", // attributes: { // author: "Mary Jane Watson", // importance: "π‘", // } // }
To make a deep copy of an object, including its nested properties, we recommend using the .cloneDeep
method from the third-party Lodash library. For setup instructions, check out our full article on object cloning.
#8: Merge objects
The properties of two or more objects can be combined by spreading their contents into a new object:
const breakfastMenu = { croissant: "π₯", bagel: "π₯―" } const lunchMenu = { spagBowl: "π", steamedRice: "π", } const fullMenu = {...breakfastMenu, ...lunchMenu}; console.log(fullMenu); //βοΈAll properties are now in new object // { // croissant: "π₯", // bagel: "π₯―" // spagBowl: "π", // steamedRice: "π", // }
Make sure that properties do not share the same key values when doing this, because otherwise properties spread earlier will be overwritten:
// β The wrong way wish clashing property keys: const breakfastMenu = { option1: "π₯", option2: "π₯―" } const lunchMenu = { option1: "π", option2: "π", } const fullMenu = {...breakfastMenu, ...lunchMenu}; console.log(fullMenu); // { // spagBowl: "π", // steamedRice: "π", // }
Summary
The spread operator performs a simple operation: listing the contents of an iterable in a comma-separated list. Due to its popularity, its use was extended to non-iterable objects in ES2018.
As demonstrated by the examples in this article, the spread operator has many and varied use cases that avoid the need for complicated workarounds.
Though incredibly useful, it is important to remember that it is not appropriate for copying arrays or objects with nesting. For this, we recommend using .deepClone
from the Lodash library.
Related links
- The Lodash library homepage
- W3Schools: React ES6 Spread Operator
- MDN Web Docs: Spread syntax (...)
- OpenJavaScript article: From JavaScript object or array to variables with destructuring assignment
- OpenJavaScript article: The right way to clone an object in JavaScript