Это не первая статья на Medium об операторе спреда и не последняя. Тем не менее, если вы запутались в этих загадочных эллипсах в Javascript и среди всех других наткнулись на мою статью, добро пожаловать! Я проведу вас через это.
Что такое оператор спреда?
Оператор распространения выглядит как ...
и, в двух словах, преобразует массив (или объект) только в его элементы.
let arr = [1, 2, 3]; console.log(...arr); // 1 2 3
Этот синтаксис является новым в ES6, поэтому вы, возможно, не сталкивались с ним, если изучали Javascript по устаревшим материалам.
Это хорошо, но как мне это использовать?
Рад, что ты спросил! Вот несколько способов, с помощью которых оператор спреда упрощает нашу жизнь.
Копировать массив
Самый простой (но не самый простой) способ скопировать массив - использовать цикл for
:
let arr = [1, 2, 3]; let copyOfArr = []; for (let i = 0; i < arr.length; i++) { copyOfArr.push(arr[i]); } console.log(copyOfArr); // [1, 2, 3]
Более смекалистый подход использует Array.slice()
:
let arr = [1, 2, 3]; let copyOfArr = arr.slice(0); console.log(copyOfArr); // [1, 2, 3]
Но проще всего использовать оператор спреда:
let arr = [1, 2, 3]; let copyOfArr = [...arr]; console.log(copyOfArr); // [1, 2, 3]
Оператор распространения берет отдельные элементы из arr
и распределяет (помещает) их в наш новый массив. Обратите внимание, что это отличается от записи [arr]
:
// NOT WHAT WE WANT let arr = [1, 2, 3]; let copyOfArr = [arr]; console.log(copyOfArr); // [[1, 2, 3]]
«Но почему мы не можем просто написать let copyOfArr = arr
?»
Хороший вопрос. Ответ: в некоторых ситуациях можно. ОДНАКО массивы и объекты Javascript передаются по ссылке, а не по значению. Это означает, что когда мы пишем let copyOfArr = arr
, наша новая переменная copyOfArr
на самом деле не является копией arr
- это ссылка, которая указывает на arr
. Итак, если мы изменим arr
, то изменится и copyOfArr
.
let arr = [1, 2, 3]; let copyOfArr = arr; arr.pop(); console.log(copyOfArr); // [1, 2]
Я предполагаю, что если бы мы хотели, чтобы copyOfArr
изменялся каждый раз, когда arr
изменения, мы, вероятно, вообще не сделали бы копию.
Добавить элемент в конец массива
Теперь, когда мы понимаем копирование, следующие примеры будут проще. Предположим, нам нужен новый массив со всем содержимым arr
, за исключением того, что теперь с новым элементом в конце. Похоже, это работа для Array.push()
.
let arr = [1, 2, 3]; let newArray = [...arr]; newArray.push(4); console.log(newArray); // [1, 2, 3, 4]
Однако, как оказалось, оператор спреда настолько мощный, что нам даже не нужно Array.push()
! Мы будем использовать оператор распространения, чтобы создать новый массив со всеми значениями arr
, за которым следует наш новый элемент или элементы:
let arr = [1, 2, 3]; let newArray = [...arr, 4]; console.log(newArray); // [1, 2, 3, 4]
Добавить элемент в начало массива
Вы, наверное, видите, к чему все идет:
let arr = [1, 2, 3]; let newArray = [0, ...arr]; console.log(newArray); // [0, 1, 2, 3]
Поместите значения массива в середину нового массива
Мы можем объединить два вышеуказанных варианта использования:
let arr = [1, 2, 3]; let newArray = [0, ...arr, 4, 5]; console.log(newArray); // [0, 1, 2, 3, 4, 5]
Объединить (объединить) массивы
Комбинирование массивов стало проще, чем когда-либо благодаря синтаксису распространения:
let oneTwo = [1, 2]; let threeFour = [3, 4]; let newArray = [...oneTwo, ...threeFour]; console.log(newArray); // [1, 2, 3, 4]
Получите максимальное значение массива
Я видел, как программисты сортируют массивы от самого высокого до самого низкого, а затем возвращают первый элемент отсортированного массива.
let values = [4, 1, 2, 5, 0]; let highestValue = values.sort((a, b) => b - a)[0]; console.log(highestValue); // 5
Если вы хотите нарядиться, вот решение, в котором используется Array.reduce()
:
let values = [4, 1, 2, 5, 0]; let highestValue = values.reduce((acc, val) => (val > acc ? val : acc), 0); console.log(highestValue); // 5
Однако наиболее логичным решением было бы использовать Math.max()
. Загвоздка в том, что мы должны передавать в Math.max()
отдельные аргументы, а это значит, что мы не можем использовать Math.max()
в массиве.
let values = [4, 1, 2, 5, 0]; let highestValue = Math.max(values); console.log(highestValue); // NaN
Если бы только существовал способ взять массив и разложить его отдельные элементы… о, подождите!
let values = [4, 1, 2, 5, 0]; let highestValue = Math.max(...values); console.log(highestValue); // 5
Теперь, когда мы знаем об операторе распространения, эти другие методы массива кажутся обходными по сравнению.
Получите наименьшее значение массива
Достаточно просто:
let values = [4, 1, 2, 5, 0]; let lowestValue = Math.min(...values); console.log(lowestValue); // 0
Удалить индекс из массива
Мы могли бы использовать для этого Array.splice()
, но давайте представим, что мы не хотим изменять исходный массив.
let arr = [1, 2, 7, 3, 4, 5, 6, 7]; // The erroneous 7 is at index 2: let i = 2; let newArray = [...arr.slice(0, i), ...arr.slice(i + 1)]; console.log(newArray); // [1, 2, 3, 4, 5, 6, 7]
Обновить объект
У вас может возникнуть ситуация, когда вам нужно вернуть объект с обновленными данными, но без изменения исходного объекта. Обратите внимание, разработчики React: это часто будет иметь место, если вы используете Redux! К счастью, оператор распространения работает с объектами. Если мы распространяем два объекта на новый объект, и оба объекта имеют общий ключ, последний объект заменит первый своим значением для этого ключа. Результат - новый объект с обновленными данными.
let youtubeVideo = { title: "PB&J tutorial (GONE WRONG) (POLICE CALLED)", likes: 2, dislikes: 1000, description: "Smash that like button and hit SUBSCRIBE!", url: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }; let updateData = { dislikes: youtubeVideo.dislikes + 1 } let updatedVideo = { ...youtubeVideo, ...updateData }; console.log(updatedVideo); // same as youtubeVideo, but now with 1001 dislikes
Остаточный синтаксис
Иногда три точки вместе на самом деле являются синтаксисом отдыха, а не синтаксисом распространения. В этом разница: если мы используем ...
для массива или объекта, это синтаксис распространения, и мы получаем его отдельные значения. Но если мы используем ...
для отдельных значений, это синтаксис отдыха, и мы получаем массив или объект. Мы можем использовать синтаксис rest для сжатия списка отдельных параметров функции в массив:
function getAverage(...numbers) { return numbers.reduce((acc, val) => acc + val) / numbers.length; } console.log(getAverage(5, 10, 50, 25, 35)); // 25
Синтаксис отдыха с React
Давайте дополним эту статью отличным примером. Допустим, у нас есть некоторые пользовательские данные, которые мы хотим преобразовать в список. Каждый раз, когда мы визуализируем список в React, нам нужно присвоить каждому элементу списка уникальный атрибут key
. Мы используем id
каждого пользователя в качестве key
и пишем что-то вроде этого:
Это достаточно просто, но что, если бы у нас были еще более подробные данные о пользователях? Представим, что мы также хотели отобразить родной город наших пользователей, адрес электронной почты, любимую еду, рост, вес, худшие опасения и т. Д. Внезапно мы обнаруживаем, что деструктурируем и выписываем множество реквизитов для UserListItem
в нашей функции map()
.
К счастью, у нас есть более простой способ. Мы деструктурируем id
для каждого пользователя, а затем воспользуемся синтаксисом rest для доступа к остальным свойствам пользователя. Затем мы перенесем эти свойства в наш UserListItem
компонент.
Наш код по-прежнему работает так же, и теперь у нас есть более гибкая и лаконичная map()
функция.
Если мы действительно хотим сделать все возможное, мы можем использовать синтаксис rest в определении компонента UserListItem
:
Надеюсь, это поможет, и спасибо за чтение!