Вступление
Оператор распространения …
, впервые появился в ES6. Это быстро стало одной из самых популярных функций. Настолько, что, несмотря на то, что он работал только с массивами, было предложено расширить его функциональные возможности на объекты. Эта функция была наконец представлена в ES9.
Цель этого руководства, которое разделено на две части, - показать вам, почему следует использовать оператор распространения, как он работает, а также подробно изучить его использование, от самого простого до самого продвинутого.
Вот краткое изложение содержания этого руководства:
Часть 1
- Почему следует использовать оператор спреда
- Клонирование массивов / объектов
- Преобразование структур, подобных массиву, в массив
- Оператор распространения как аргумент
- Добавление элементов в массивы / объекты
- Объединение массивов / объектов
Часть 2
- Расширенное использование оператора спреда
Почему вам следует использовать оператор спреда
Прочитав предыдущий список, вы можете подумать примерно так: «Но в JavaScript есть функции для выполнения всех этих задач. Зачем мне использовать оператор распространения? » Позвольте мне познакомить вас с неизменностью.
Из Oxford Lexico: Неизменяемость - неизменна во времени или не может быть изменена.
В разработке программного обеспечения мы используем термин неизменяемый для обозначения значений, состояние которых не может изменяться с течением времени. Фактически, большинство значений, которые мы обычно используем (примитивные значения, такие как строки, целые числа и т. Д.), Неизменяемы.
Однако, когда дело касается массивов и объектов, JavaScript ведет себя особенным образом; на самом деле они изменчивы. Это может стать большой проблемой. Вот пример, поясняющий, почему:
Как видно из предыдущего фрагмента кода, у нас есть файл Squirtle. У нашего Сквиртла 100 очков здоровья, так как мы только что посетили Центр покемонов.
Поскольку нам нужен еще один сквиртл, мы объявляем переменную anotherSquirtle
, присвоив ее исходному сквиртлу значение. После тяжелой битвы anotherSquirtle
терпит поражение. Поэтому мы получаем доступ к HP anotherSquirtle
и меняем его на 0. Следующим шагом будет проверка нашего исходного Squirtle. Мы console.log
и…
Чего ждать? HP нашего оригинального Squirtle упал до 0. Как это может быть? Что случилось с нашим бедным Сквиртлом? Произошла мутация JavaScript. Позвольте мне объяснить, что происходит.
Когда мы создали переменную anotherSquirtle
и присвоили нашему исходному Squirtle в качестве ее значения, на самом деле мы назначили ссылку на место в памяти исходного объекта Squirtle. Это связано с тем, что массивы и объекты JavaScript являются ссылочными типами данных. В отличие от примитивных типов данных, они указывают на адрес памяти, где хранится фактический объект / массив.
Чтобы упростить понимание, вы можете представить ссылочные типы данных как указатели на глобальную переменную. Изменяя значение ссылочного типа данных, мы на самом деле меняем значение глобальной переменной.
Это означает, что когда мы изменили значение HP для anotherSquirtle
на 0, мы действительно изменили значение HP объекта Squirtle, хранящегося в памяти, на 0. Вот почему mySquirtle
' значение HP равно 0 - потому что mySquirtle
содержит ссылку на объект, хранящийся в памяти, который мы изменили с помощью переменной anotherSquirtle
. Спасибо, JavaScript.
Как решить эту проблему?
Чтобы избежать случайного изменения переменных, нам нужно создать новый экземпляр нашего массива / объекта всякий раз, когда мы хотим скопировать массив / объект. Как нам этого добиться?
С оператором распространения.
Как работает оператор спреда?
Из документации MDN: Синтаксис Spread позволяет развернуть итерацию, например выражение массива или строку, в местах, где ожидается 0 или более аргументов (для вызовов функций) или элементов (для литералов массива) или выражение объекта, которое должно быть развернуто в местах, где ожидается 0 или более пар ключ-значение (для объектных литералов).
Проще говоря, оператор распространения …
распределяет элементы, содержащиеся в итерируемом объекте (итерабельный - это все, что можно перебрать, например строки, массивы, наборы и т. Д.) Внутри получатель. (Приемник - это то, что принимает значения спреда.) Вот несколько простых примеров с массивами, которые позволят вам лучше понять это:
Как видите, когда мы используем оператор распространения в массиве, мы получаем e каждый отдельный элемент, содержащийся в массиве. Во всех предыдущих случаях получателем была функция, функция console.log
. Достаточно просто, правда?
Клонирование массивов и объектов
Теперь, когда мы знаем, как работает оператор распространения, мы можем использовать его для неизменного копирования массивов и объектов. Как? Распространяя содержимое, а затем используя литералы массива или объекта ([]
и {}
соответственно) для создания нового экземпляра массива / объекта.
Давайте возьмем предыдущий пример Сквиртла и исправим его путем неизменного клонирования mySquirtle
variable:
Деструктурируя содержимое переменной mySquirtle
с помощью оператора распространения и используя литерал объекта, мы создаем новый экземпляр объекта Squirtle. Таким образом мы предотвращаем случайную мутацию переменной.
Чтобы скопировать массив, мы используем точно такой же синтаксис:
Примечание. Имейте в виду, что оператор распространения выполняет только неглубокие копии. Это означает, что если у вас есть ссылочный тип данных, хранящийся внутри вашего массива / объекта, когда вы делаете копию с помощью оператора распространения, вложенный массив / объект будет содержать ссылку на оригинал и, таким образом, будет изменчивым.
Преобразование объектов, подобных массиву, в массивы
Объекты, подобные массивам, очень похожи на массивы. Обычно они имеют пронумерованные элементы и свойство длины. Однако у них есть одно важное отличие: объекты, подобные массивам, не имеют никаких функций массива.
Среди объектов, подобных массиву, есть списки узлов HTML, возвращаемые большинством методов DOM, переменные аргументов, автоматически сгенерированные в каждой функции JS, и некоторые другие.
С тем же синтаксисом, что и при клонировании массивов, мы можем использовать оператор распространения для преобразования структур, подобных массиву, в массивы в качестве альтернативы использованию Array.from
. Вот пример преобразования nodeList
в массив:
С помощью этого метода мы можем преобразовать любую структуру, подобную массиву, в массив и, таким образом, получить доступ ко всем функциям массива.
Оператор распространения как аргумент
Некоторые функции принимают переменное количество параметров. Прекрасным примером таких функций являются функции из коллекции Math
. В нашем примере возьмем функцию Math.max()
, которая принимает n числовых параметров и возвращает наибольший из них. Представьте, что у нас есть массив чисел, который мы хотим передать функции Math.max()
. Как мы делаем это?
Мы могли бы сделать что-то вроде этого (не зли меня за следующий код):
Но, конечно, это было бы самоубийством. Что, если бы у нас было 20 значений? Или 1000? Собираемся ли мы обращаться к каждому значению по индексу? Ответ - нет. Как мы уже знаем, оператор распространения берет массив и извлекает каждое отдельное значение. Это именно то, что мы ищем. Следовательно, мы можем сделать это:
Оператор разворота спешит на помощь.
Добавление новых элементов
Добавление элементов в массив
Чтобы добавить новые элементы в массив, мы сначала распределяем содержимое массива и используем литерал массива []
для создания нового экземпляра массива, содержащего содержимое исходного массива плюс значения, которые мы хотим добавить:
Как видите, мы можем добавить столько новых элементов, сколько захотим.
Добавление свойств к объекту
Используя тот же синтаксис, что и для массивов, мы можем легко добавлять новые свойства при клонировании объекта. Чтобы немного изменить его, вот другой синтаксис для добавления свойств к объекту (его также можно использовать с массивами):
Как видите, мы можем объявлять и инициализировать новые переменные непосредственно внутри литерала объекта, а не делать это снаружи.
Слияние массивов / объектов
Массивы
Мы можем объединить два массива, раздвинув их и используя литерал массива, как в предыдущих примерах. Однако вместо того, чтобы просто добавлять новый элемент, мы собираемся добавить еще один массив (спред):
Это также работает, если у нас есть массив объектов:
Объекты
Мы можем объединить два (или более) объекта в один объект, используя тот же синтаксис, что и раньше (вы, возможно, уже заметили, что оператор распространения используется очень похожим образом как для массивов, так и для объектов):
Заключение
В этой первой части руководства мы узнали, почему мы должны использовать оператор распространения (неизменность!), Как он работает, и несколько основных способов использования этого оператора. Во второй части руководства мы углубим наши знания об этом операторе с помощью нескольких передовых методов и вариантов использования. Вот ссылка на вторую часть учебника:
Понимание оператора распространения JavaScript - расширенное использование
Большое спасибо за чтение.