Спред-синтаксис ...

Упрощает создание объектов и массивов на основе других объектов и массивов.

Время чтения: 5 мин

Кратко

Скопировано

Спред-синтаксис (spread) ... позволяет передавать итерируемые коллекции (например, массивы или строки) как список аргументов функции или добавлять содержащиеся в них элементы в новый массив.

Спред применятся и для объектов, чтобы копировать пары ключ-значение из одного объекта в другой.

Пример

Скопировано

При вызове функции использовать значения из массива как аргументы:

        
          
          function multiplyThreeNumbers(a, b, c) {  return a * b * c}const nums = [1, 2, 3]console.log(multiplyThreeNumbers(...nums))// 6
          function multiplyThreeNumbers(a, b, c) {
  return a * b * c
}

const nums = [1, 2, 3]

console.log(multiplyThreeNumbers(...nums))
// 6

        
        
          
        
      

В массиве скопировать элементы из другого массива в новый:

        
          
          const donor = ['это', 'старые', 'значения']const newArray = [...donor, 1, true, 'мама']console.log(newArray)// ['это', 'старые', 'значения', 1, true, 'мама']
          const donor = ['это', 'старые', 'значения']
const newArray = [...donor, 1, true, 'мама']

console.log(newArray)
// ['это', 'старые', 'значения', 1, true, 'мама']

        
        
          
        
      

У объекта скопировать свойства из другого объекта в новый:

        
          
          const persona = { name: 'Иван', lastName: 'Объектов'}const userData = { ...persona, username: 'killer3000' }console.log(userData)// {//    name: 'Иван',//    lastName: 'Объектов',//    username: 'killer3000'// }
          const persona = { name: 'Иван', lastName: 'Объектов'}
const userData = { ...persona, username: 'killer3000' }

console.log(userData)
// {
//    name: 'Иван',
//    lastName: 'Объектов',
//    username: 'killer3000'
// }

        
        
          
        
      

Как понять

Скопировано

Спред-синтаксис легче всего изучать на примерах. Есть три контекста, в которых он применяется.

При вызове функции

Скопировано

Часто встречается ситуация, когда мы хотим использовать данные из итерируемой коллекции в качестве аргументов функции. Чаще всего такая коллекция — массив. Если функция не умеет принимать массив аргументом, то придётся доставать элементы вручную:

        
          
          function multiplyThreeNumbers(a, b, c) {  return a * b * c}const nums = [1, 2, 3]console.log(multiplyThreeNumbers(nums[0], nums[1], nums[2]))// 6
          function multiplyThreeNumbers(a, b, c) {
  return a * b * c
}

const nums = [1, 2, 3]

console.log(multiplyThreeNumbers(nums[0], nums[1], nums[2]))
// 6

        
        
          
        
      

Если элементов становится больше, доставать значения вручную становится неудобно. Чтобы решить эту проблему, в старых версиях языка использовали метод apply(). Этот метод принимает первым аргументом значение this, а вторым — список аргументов для вызова функции:

        
          
          function multiplyThreeNumbers(a, b, c) {  return a * b * c}const nums = [1, 2, 3]console.log(multiplyThreeNumbers.apply(null, nums))// 6
          function multiplyThreeNumbers(a, b, c) {
  return a * b * c
}

const nums = [1, 2, 3]

console.log(multiplyThreeNumbers.apply(null, nums))
// 6

        
        
          
        
      

Такой синтаксис сложно читается, его нельзя использовать при создании объектов с помощью конструктора new. Его упростили до спред-синтаксиса. В этом случае элементы как бы выкладываются из списка в нужном порядке:

        
          
          function multiplyThreeNumbers(a, b, c) {  return a * b * c}const nums = [1, 2, 3]console.log(multiplyThreeNumbers(...nums))// 6
          function multiplyThreeNumbers(a, b, c) {
  return a * b * c
}

const nums = [1, 2, 3]

console.log(multiplyThreeNumbers(...nums))
// 6

        
        
          
        
      

Если в массиве будет больше элементов, чем параметров функции, то будут использованы только те элементы, которые идут первыми по порядку:

        
          
          function multiplyThreeNumbers(a, b, c) {  return a * b * c}const nums = [1, 2, 3, 5, 6]console.log(multiplyThreeNumbers(...nums))// 6
          function multiplyThreeNumbers(a, b, c) {
  return a * b * c
}

const nums = [1, 2, 3, 5, 6]

console.log(multiplyThreeNumbers(...nums))
// 6

        
        
          
        
      

При создании массивов с помощью литерала []

Скопировано

Спред-синтаксис решает задачу создания нового массива с использованием данных из другого массива. Без него неудобно создавать массив, который содержит элементы другого. Приходится использовать методы массива, например, concat():

        
          
          const watchedMovies = ['Rocky', 'Terminator 2', 'The Matrix']const watchedVideos = ['Rick&Morty', 'lofi hip hop radio'].concat(watchedMovies)console.log(watchedVideos)// ['Rick&Morty', 'lofi hip hop radio', 'Rocky', 'Terminator 2', 'The Matrix']
          const watchedMovies = ['Rocky', 'Terminator 2', 'The Matrix']
const watchedVideos = ['Rick&Morty', 'lofi hip hop radio'].concat(watchedMovies)

console.log(watchedVideos)
// ['Rick&Morty', 'lofi hip hop radio', 'Rocky', 'Terminator 2', 'The Matrix']

        
        
          
        
      

Спред решает эту проблему лучше:

        
          
          const watchedMovies = ['Rocky', 'Terminator 2', 'The Matrix']const watchedVideos = ['Rick&Morty', 'lofi hip hop radio', ...watchedMovies]console.log(watchedVideos)// ['Rick&Morty', 'lofi hip hop radio', 'Rocky', 'Terminator 2', 'The Matrix']
          const watchedMovies = ['Rocky', 'Terminator 2', 'The Matrix']
const watchedVideos = ['Rick&Morty', 'lofi hip hop radio', ...watchedMovies]

console.log(watchedVideos)
// ['Rick&Morty', 'lofi hip hop radio', 'Rocky', 'Terminator 2', 'The Matrix']


        
        
          
        
      

Таким образом можно создать копию существующего массива:

        
          
          const watchedMovies = ['Rocky', 'Terminator 2', 'The Matrix']const myWatchedMovies = [...watchedMovies]
          const watchedMovies = ['Rocky', 'Terminator 2', 'The Matrix']
const myWatchedMovies = [...watchedMovies]

        
        
          
        
      

Или склеить несколько массивов в один:

        
          
          const movies = ['Rocky', 'Terminator 2', 'The Matrix']const series = ['Prison Break', 'Rick&Morty', 'Lost']const watched = [...movies, ...series]// [//  'Rocky',//  'Terminator 2',//  'The Matrix',//  'Prison Break',//  'Rick&Morty',//  'Lost'// ]
          const movies = ['Rocky', 'Terminator 2', 'The Matrix']
const series = ['Prison Break', 'Rick&Morty', 'Lost']

const watched = [...movies, ...series]
// [
//  'Rocky',
//  'Terminator 2',
//  'The Matrix',
//  'Prison Break',
//  'Rick&Morty',
//  'Lost'
// ]

        
        
          
        
      

Пример поведения с уровнем вложенности больше одного:

        
          
          const users = [{ name: 'Иван', lastName: 'Объектов' }]const copyUsers = [...users]copyUsers[0].name = 'Николай'console.log(users[0])// { name: 'Николай', lastName: 'Объектов' }
          const users = [{ name: 'Иван', lastName: 'Объектов' }]
const copyUsers = [...users]

copyUsers[0].name = 'Николай'
console.log(users[0])
// { name: 'Николай', lastName: 'Объектов' }

        
        
          
        
      

При создании объекта с помощью литерала {}

Скопировано

По аналогии с массивами, спред-синтаксис решает проблему копирования свойств в новый объект. В версии языка без спреда для копирования использовался метод Object.assign(), который принимал два объекта — куда копировать свойства и откуда:

        
          
          const person = { name: 'Иван', lastName: 'Объектов' }const userData = Object.assign({ username: 'killer3000' }, person)console.log(userData)// {//    name: 'Иван',//    lastName: 'Объектов',//    username: 'killer3000'// }
          const person = { name: 'Иван', lastName: 'Объектов' }
const userData = Object.assign({ username: 'killer3000' }, person)

console.log(userData)
// {
//    name: 'Иван',
//    lastName: 'Объектов',
//    username: 'killer3000'
// }

        
        
          
        
      

Спред упрощает код и делает его читабельнее:

        
          
          const person = { name: 'Иван', lastName: 'Объектов' }const userData = { username: 'killer3000', ...person }console.log(userData)// {//    name: 'Иван',//    lastName: 'Объектов',//    username: 'killer3000'// }
          const person = { name: 'Иван', lastName: 'Объектов' }
const userData = { username: 'killer3000', ...person }

console.log(userData)
// {
//    name: 'Иван',
//    lastName: 'Объектов',
//    username: 'killer3000'
// }

        
        
          
        
      

Если свойства в новом и старом объекте совпадают, то будет использоваться значение свойства, которое шло последним:

        
          
          const person = { name: 'Иван', lastName: 'Объектов' }const userData = { name: 'Николай', ...person }console.log(userData)// { name: 'Иван', lastName: 'Объектов' }
          const person = { name: 'Иван', lastName: 'Объектов' }
const userData = { name: 'Николай', ...person }

console.log(userData)
// { name: 'Иван', lastName: 'Объектов' }

        
        
          
        
      

Если поставить спред в начало, то будет использоваться новое имя:

        
          
          const person = { name: 'Иван', lastName: 'Объектов' }const userData = { ...person, name: 'Николай' }console.log(userData)// { name: 'Николай', lastName: 'Объектов' }
          const person = { name: 'Иван', lastName: 'Объектов' }
const userData = { ...person, name: 'Николай' }

console.log(userData)
// { name: 'Николай', lastName: 'Объектов' }

        
        
          
        
      

На практике

Скопировано

Николай Лопин советует

Скопировано

🛠 Спред на объектах используют в библиотеке React. Программист может передать в функцию объект с произвольными свойствами, но мы хотим запретить устанавливать некоторые из них. В этом случае создаётся новый объект, в который сначала копируются присланные значения, а потом значения «запрещённых» свойств. В этом случае даже если запрещённое свойство было передано, оно будет перезаписано:

        
          
          function Headline(props) {  const filteredProps = {...props, ariaHidden: false}  return createElement('h1', filteredProps, 'Текст заголовка')}
          function Headline(props) {
  const filteredProps = {...props, ariaHidden: false}
  return createElement('h1', filteredProps, 'Текст заголовка')
}

        
        
          
        
      

На собеседовании

Скопировано
Задать вопрос в рубрику
🤚 Я знаю ответ

Скопировано

Rest- и spread-операторы являются частью синтаксиса JavaScript. Они выполняют разные функции, хотя могут быть похожи в некоторых случаях. Давайте рассмотрим их отличия.

Оператор rest (...)

Скопировано

Rest-оператор используется для сбора оставшихся аргументов функции в массив.

        
          
          function sum(...args) {  return args.reduce((total, num) => total + num, 0)}console.log(sum(1, 2, 3, 4))// 10
          function sum(...args) {
  return args.reduce((total, num) => total + num, 0)
}
console.log(sum(1, 2, 3, 4))
// 10

        
        
          
        
      

Таким образом можно обрабатывать неизвестное количество аргументов, переданных в функцию.

Оператор spread (...)

Скопировано

Spread-оператор используется для распространения элементов массива или свойств объекта.

        
          
          const arr1 = [1, 2, 3]const arr2 = [4, 5, 6]const combinedArray = [...arr1, ...arr2]console.log(combinedArray)// [1, 2, 3, 4, 5, 6]
          const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]
const combinedArray = [...arr1, ...arr2]
console.log(combinedArray)
// [1, 2, 3, 4, 5, 6]

        
        
          
        
      

Оператор spread также используется для создания поверхностных копий массивов или объектов.

        
          
          const originalArray = [1, 2, 3]const copiedArray = [...originalArray]console.log(copiedArray)// [1, 2, 3]
          const originalArray = [1, 2, 3]
const copiedArray = [...originalArray]
console.log(copiedArray)
// [1, 2, 3]

        
        
          
        
      

Таким образом, основное отличие между rest- и spread-операторами заключается в их применении. Rest используется для сбора аргументов в функции, тогда как spread — для распространения элементов массивов или объектов.

Ирина Аринушкина  отвечает

Скопировано

Операторы spread и rest выглядят одинаково, как три точки — ..., но выполняют противоположные действия.

Что делает оператор rest?

Скопировано

Собирает оставшиеся аргументы функции в массив. Этот синтаксис используется при объявлении функции.

        
          
          function doSomething(first, second, ...array) {  console.log(first, second, array)}doSomething(1, 2, 3, 4, 5)// 1 2 [3, 4, 5]
          function doSomething(first, second, ...array) {
  console.log(first, second, array)
}
doSomething(1, 2, 3, 4, 5)
// 1 2 [3, 4, 5]

        
        
          
        
      

Собирает оставшиеся элементы массива в новый массив. Используется при деструктуризации массива.

        
          
          const [first, second, ...array] = [1, 2, 3, 4, 5]console.log(first, second, array)// 1 2 [3, 4, 5]
          const [first, second, ...array] = [1, 2, 3, 4, 5]
console.log(first, second, array)
// 1 2 [3, 4, 5]

        
        
          
        
      

Собирает оставшиеся свойства объекта в новый объект. Используется при деструктуризации объекта.

        
          
          const { c, ...object } = { a: 1, b: 2, c: 3 }console.log(c, object)// 3 {a: 1, b: 2}
          const { c, ...object } = { a: 1, b: 2, c: 3 }
console.log(c, object)
// 3 {a: 1, b: 2}

        
        
          
        
      

⛔ Оператор rest собирает все оставшиеся элементы, свойства или аргументы функции, если написать что-то после них, это вызовет ошибку:

        
          
          const [first, second, ...array, five] = [1, 2, 3, 4, 5]// five после ...array// Ошибка!
          const [first, second, ...array, five] = [1, 2, 3, 4, 5]
// five после ...array
// Ошибка!

        
        
          
        
      

Что делает оператор spread?

Скопировано

Раскладывает массив на отдельные аргументы при вызове функции.

        
          
          function doSomething(first, second, third) {  console.log(first, second, third)}const array = [1, 2, 3]doSomething(...array)// 1 2 3
          function doSomething(first, second, third) {
  console.log(first, second, third)
}
const array = [1, 2, 3]
doSomething(...array)
// 1 2 3

        
        
          
        
      

Раскладывает массив на отдельные элементы. Этот синтаксис используется при создании массива с помощью литерала [].

        
          
          const array = [3, 4]const newArray = [1, 2, ...array, 5]console.log(newArray)// [1, 2, 3, 4, 5]
          const array = [3, 4]
const newArray = [1, 2, ...array, 5]
console.log(newArray)
// [1, 2, 3, 4, 5]

        
        
          
        
      

Раскладывает объект на отдельные свойства. Этот синтаксис используется при создании объекта с помощью литерала {}.

        
          
          const object = { b: 2, c: 3 }const newObject = { a: 1, ...object }console.log(newObject)// { a: 1, b: 2, c: 3}
          const object = { b: 2, c: 3 }
const newObject = { a: 1, ...object }
console.log(newObject)
// { a: 1, b: 2, c: 3}

        
        
          
        
      

Оператор spread может стоять где угодно и использоваться любое количество раз в рамках одного вызова функции или создания массива, объекта.

Так тоже можно:

        
          
          const firstArray = [3, 4]const secondArray = [15, 16]const newArray = [1, 2, ...firstArray, 5, ...secondArray]console.log(newArray)// [1, 2, 3, 4, 5, 15, 16]
          const firstArray = [3, 4]
const secondArray = [15, 16]
const newArray = [1, 2, ...firstArray, 5, ...secondArray]
console.log(newArray)
// [1, 2, 3, 4, 5, 15, 16]