Вступление

Оператор распространения , впервые появился в ES6. Это быстро стало одной из самых популярных функций. Настолько, что, несмотря на то, что он работал только с массивами, было сделано предложение расширить его функциональные возможности на объекты. Эта функция была наконец представлена ​​в ES9.

Цель этого руководства, которое разделено на две части, - показать вам, почему следует использовать оператор распространения, как он работает, а также подробно изучить его использование, от самого простого до самого продвинутого.

Если вы еще не прочитали первую часть этого урока, я рекомендую вам это сделать!

Вот краткое изложение содержания этого руководства:

Часть 1

  1. Почему следует использовать оператор спреда.
  2. Клонирование массивов / объектов.
  3. Преобразование структур, подобных массиву, в массив.
  4. Оператор распространения в качестве аргумента.
  5. B Добавление элементов в массивы / объекты.
  6. Объединение массивов / объектов.

Часть 2

  1. Разрушение вложенных элементов.
  2. Добавление условных свойств.
  3. Короткое замыкание.
  4. Остальной параметр .
  5. Значения деструктуризации по умолчанию.
  6. Свойства по умолчанию.

Клонирование массивов / объектов с вложенными элементами

В первой части этой статьи мы узнали о ссылочных типах данных, случайном изменении переменных и о том, как можно решить эту проблему путем неизменного клонирования массивов / объектов с помощью оператора распространения.

Однако, когда речь идет о вложенных ссылочных типах данных, у этого подхода есть небольшая проблема. Оператор распространения выполняет только неглубокий клон.

Что это значит? Если мы попытаемся клонировать объект, содержащий массив, например, массив внутри клонированного объекта будет содержать ссылку на адрес памяти, где хранится исходный массив ...

Это означает, что, хотя наш объект является неизменяемым, массив внутри него - нет. Вот пример, чтобы проиллюстрировать это:

Как видите, наш squirtleClone был клонирован безвозвратно. Когда мы меняем свойство name исходного объекта pokemon на Charmander, наш squirtleClone не изменяется, его свойство name не изменяется.

Однако, когда мы добавляем новую способность к свойству abilities исходного объекта pokemon ... Это изменение влияет на наши способности squirtleClone. Поскольку свойство abilities является ссылочным типом данных, оно не клонируется безоговорочно. Добро пожаловать в реальность JavaScript.

Одним из решений этой проблемы было бы использование оператора распространения для клонирования вложенных свойств, как показано в следующем примере:

По понятным причинам это не идеальный подход к решению нашей проблемы. Нам нужно будет использовать оператор распространения для каждого отдельного свойства ссылочного типа, поэтому этот подход применим только для небольших объектов.

Итак, какое оптимальное решение? Глубокое клонирование .

Поскольку о глубоком клонировании можно много сказать, я не буду вдаваться в подробности. Я просто хочу сказать, что правильный способ глубокого клонирования - это либо использовать внешнюю библиотеку (например, Lodash), либо написать себе функцию, которая это делает.

Добавление условных свойств

Иногда нам нужно добавить свойства к объекту, но мы не знаем, существуют ли эти свойства. Это не представляет особой проблемы, мы всегда можем проверить, существует ли свойство, с помощью оператора if:

Однако есть гораздо более простой способ добиться того же результата, используя сокращающие условные выражения с помощью оператора &&. Краткое объяснение:

Короткое замыкание

Когда мы оцениваем выражение с &&, если первый операнд false, JavaScript закоротит и проигнорирует второй операнд.

Давайте посмотрим на следующий код:

Если starterPokemon.length > 0 ложно (массив пуст), оператор будет закорочен, и наша функция choosePokemon никогда не будет выполнена. Вот почему предыдущий код эквивалентен использованию традиционного оператора if.

Возвращаясь к нашей исходной проблеме, мы можем воспользоваться преимуществом логического оператора AND для добавления условных свойств к объекту. Вот как:

Что тут происходит? Позвольте мне объяснить.

Как мы уже знаем, при использовании оператора && вторая часть оператора будет выполняться только в том случае, если первый операнд истинен.

Следовательно, только если переменная abilities истинна (если переменная существует), будет выполнена вторая половина оператора. Что делает эта вторая половина?

Он создает объект, содержащий переменную abilities, которая затем деструктурируется с помощью оператора распространения, помещенного перед оператором, таким образом добавляя существующую переменную abilities в наш объект fullPokemon.

Прежде чем мы сможем представить наше окончательное расширенное использование распространения, добавляя свойства по умолчанию к объектам, мы должны сначала погрузиться в две новые концепции: значения деструктуризации по умолчанию и параметр rest.

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

Значения деструктуризации по умолчанию

Если мы попытаемся деструктурировать несуществующий элемент массива или свойство объекта, мы получим неопределенную переменную. Как избежать неопределенных значений? Используя значения по умолчанию. Как это работает?

Мы можем присвоить значения по умолчанию переменным, которые мы деструктурируем, внутри фактического оператора деструктуризации. Вот пример:

Как видите, добавляя значение по умолчанию Water к переменной type в операторе деструктуризации, мы избегаем неопределенной переменной в случае объекта pokemon, не имеющего свойства type.

Остаточный параметр (…)

Вы можете быть удивлены, узнав, что оператор распространения перегружен. Это означает, что он выполняет несколько функций. Его вторая функция - действовать как остаточный параметр.

Последний параметр функции может иметь префикс ..., что приведет к тому, что все оставшиеся (предоставленные пользователем) аргументы будут помещены в« стандартный массив javascript. Только последний параметр может быть параметром отдыха ». - Документы MDN

Проще говоря, оператор rest берет все оставшиеся элементы ( поэтому он назван rest, как и остальные элементы) и помещает их в массив. Вот пример:

Как видите, мы можем передать функции printPokemon столько возможностей, сколько захотим. Каждое отдельное значение, которое мы вводим после параметра типа (остальные параметры), будет собрано в массив, который затем мы преобразуем в строку с функцией join и распечатаем.

Примечание. Помните, что оставшийся параметр должен быть последним параметром, иначе произойдет ошибка.

Остальной параметр также можно использовать при деструктуризации, которая нас интересует. Это позволяет нам получить оставшиеся свойства объекта и сохранить их.

Вот пример остаточного параметра, используемого в деструктурирующем назначении:

Как показано выше, мы можем использовать параметр rest для деструктуризации оставшихся свойств в объекте pokemon. Как и в предыдущем примере, наш объект pokemon может иметь столько свойств, сколько мы хотим определить после id , все они будут собраны параметром rest.

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

Добавление свойств по умолчанию

Иногда у нас есть большое количество похожих объектов, которые не совсем одинаковые. Некоторым из них не хватает свойств, которые есть у других объектов. Однако нам нужно, чтобы все наши объекты имели одинаковые свойства. Как мы можем этого добиться?

Установив свойства по умолчанию. Это свойства со значением по умолчанию, которое будет добавлено к нашему объекту, если у него еще нет этого свойства.

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

Что происходит в предыдущем фрагменте кода? Давайте разберемся:

Как видите, когда мы деструктурируем свойство abilities , мы добавляем значение по умолчанию []. Как мы уже знаем, значение по умолчанию будет присвоено переменной способностей только в том случае, если ее нет в объекте pokemon.

В той же строке мы собираем оставшиеся свойства (имя и тип) объекта pokemon в переменную с именем rest, используя параметр awesome rest.

В строке 7 мы распространяем остальную переменную (которая, как вы можете видеть, является объектом, содержащим свойства name и type) внутри литерала объекта, чтобы сгенерировать новый объект.

Мы также добавляем переменную abilities, которая в данном случае является пустым массивом, поскольку это то, что мы указали в качестве значения по умолчанию в предыдущей строке.

В случае, если наш исходный объект pokemon уже имеет свойство abilities, предыдущий код не изменил бы его, и он сохранил бы свое исходное значение.

Итак, вот как мы добавляем к объекту свойства по умолчанию. Давайте поместим предыдущий код в функцию и применим его к большой коллекции объектов:

Как видите, все pokemon в массиве теперь имеют свойство abilities.

В случае charmander и bulbasur у них есть пустой массив, так как это значение по умолчанию, которое мы присвоили. Однако объект squirtle сохраняет свой первоначальный набор возможностей.

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

Однако я хотел показать новый интересный способ сделать это, используя комбинацию значений по умолчанию, параметра rest и оператора распространения. Затем вы можете выбрать, какой подход вам больше всего подходит.

Заключение

Это вторая и последняя часть руководства Общие сведения об операторе распространения JavaScript - от новичка до эксперта . Вот ссылка на первую часть.

В этой второй части руководства мы изучили некоторые более сложные способы использования оператора распространения, которые включают деструктуризацию вложенных элементов, добавление условных свойств и добавление свойств по умолчанию.

Мы также узнали три интересных концепции JS: короткое замыкание, значения деструктуризации по умолчанию и остальные параметры.

Я искренне надеюсь, что вы нашли эту статью полезной, спасибо за чтение.