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

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

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

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

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

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

Скорее всего, если вы веб-разработчик, вы встретите больше программ, написанных без использования методов FP. Итак, зачем тратить время на изучение этой парадигмы эзотерического программирования?

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

Вероятно, вы были в ситуации, когда отслеживали переменную по строкам файла JavaScript, отчаянно пытаясь найти точную строку, в которой она превращается в undefined.

Это то, что я имел в виду, когда сказал, что FP позволяет нам меньше думать. Когда переменная определена, ей присваивается какое-то значение, и это значение никогда не изменится. Период.

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

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

Функциональное программирование - это не то, что вы должны ставить перед качеством вашего кода. Цель FP - помочь нам написать лучший и чище код, поэтому, если ваш код будет намного чище и легче для понимания, если вы измените переменную, пусть будет так.

В оставшейся части статьи мы рассмотрим, как мы можем применить это на практике в современных программах, написанных с помощью JavaScript.

Вы использовали неизменность

Когда мы говорим о неизменности, мы слишком много делаем упор на переменную сторону вещей. Как нельзя менять ценности. На самом деле нам следует уделять больше внимания нашим функциям и писать их с учетом неизменности.

Цель этой серии статей - показать, как используются шаблоны функционального программирования. На самом деле вы сталкивались с неизменяемостью в повседневном кодировании на JavaScript, но, вероятно, не уделяли этому много внимания. Давайте рассмотрим некоторые встроенные функции языка.

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

Когда я впервые столкнулся с этим, я был немного разочарован. Какой смысл вызывать эту функцию, например, в массиве, если она на самом деле не изменяет массив, который я вызвал ?! Я всегда забывал об этом, и это было единственной причиной целой кучи ошибок в моих программах. Честно говоря, мне потребовалось больше времени, чем следовало бы, чтобы понять преимущества такого подхода.

Декларативный против итеративного

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

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

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

В тот момент, когда это щелкнуло для меня, я перестал писать петли. Честно говоря, я не могу вспомнить, когда в последний раз писал цикл на JavaScript. Использование этого шаблона помогло мне написать более короткий, чистый и лучше структурированный код.

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

На самом деле вы, вероятно, будете перебирать набор данных, выполняя некоторые условные проверки, а затем изменяя значения и в конце что-то вычисляя. Позвольте мне показать вам, насколько проще это читать по сравнению с циклами, если дать функциям, указанным выше, правильное именование.

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

Каждый раз, когда вы пишете цикл, подумайте, поймете ли вы, что написали, через год. Теперь взгляните на этот код - независимо от того, когда вы на него смотрите, довольно ясно, что он делает и в каком порядке.

Что-нибудь более практичное?

Если вы все еще не уверены в том, как можно расширить возможности неизменяемости, давайте обратим наши взоры на React. В частности, это интеграция с Redux. Если вы не знакомы с Redux, возможно, вам стоит сначала прочитать об этом.

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

Однако мантра Redux - никогда не изменять состояние! Вместо этого в редукторах вы всегда должны возвращать новый объект вместо предыдущего состояния.

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

Чтобы показать это по-разному в разных ситуациях, взгляните на удаление элемента из состояния. Этот редуктор использует функцию omit из lodash, чтобы удалить элемент из состояния и вернуть совершенно новый объект.

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

Однако это позволяет использовать одну из самых мощных функций в разработке Redux - отладку во времени. Поскольку в любой момент состояние вашего приложения может напоминать объект с определенными свойствами, если мы заменим его другим объектом, который придерживается того же интерфейса, мы сможем полностью изменить пользовательский интерфейс нашего приложения.

Отладка путешествия во времени позволяет вам отслеживать все предыдущие состояния вашего приложения и быстро изменять пользовательский интерфейс одним щелчком мыши - он просто меняет местами объекты.

Попался

С появлением ES6 мы получили ключевое слово const. С его помощью мы можем создавать переменные, которым нельзя присвоить другое значение. Фактически, если вы создадите экземпляр переменной с помощью const, а затем попытаетесь присвоить ей другое значение, вы получите сообщение об ошибке.

Но это не был бы JavaScript, если бы в этом не было чего-то странного, не так ли? Даже если вы не можете полностью изменить значение, вы все равно можете изменить его.

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

Спасибо, если вы дочитали до сих пор. Удерживайте кнопку хлопка, если вы нашли что-то интересное в этой статье!

Следующий

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