☕ 25 полезных сниппетов JavaScript для вашей коллекции
Подборка полезных фрагментов кода на JavaScript для решения распространенных задач программирования. Этот джентльменский набор сниппетов пригодится любому разработчику.
В программировании есть классические задачи, которые повторяются от проекта к проекту. Натыкаясь на них в десятый раз, вы начинаете задумываться о создании базы сниппетов, чтобы не писать один и тот же код с нуля. В этой статье мы собрали 25 таких трюков, которые вам обязательно пригодятся.
1. Проверка типа
JavaScript не имеет сильной системы типов, что многие считают серьезным недостатком. Поклонники строгости по достоинству оценят TypeScript, но и в самом JS есть некоторые полезные возможности. Например, провести простую проверку типа можно с помощью ключевого слова typeof.
Однако его возможности ограничены. С примитивами и функциями все работает как надо, но массивы от простых объектов вы отличить не сможете – они все имеют тип object. И не будем забывать про null, который тоже object, о чем часто забывают.
Давайте соберем все возможные проверки в одну полезную функцию:
Часто требуется определить, является ли значение пустым. Однако само понятие пустоты разное для разных типов данных. Например, в пустой строке нет символов, а в пустом объекте – ключей. Соответственно, нужно использовать разные методы:
4. Генератор случайного числа в заданном диапазоне
Эта функция достаточно проста, чтобы не использовать для генерирования случайных чисел отдельную библиотеку, но недостаточно проста, чтобы ее запомнить. Поэтому многие разработчики каждый раз обращаются к Google в поисках заветных строк:
Если вам просто нужен уникальный идентификатор (а не что-то сложное вроде UUID), то вы вполне можете обойтись без специальных библиотек. Используйте текущее время, инкремент или символы алфавита:
В JavaScript очень не хватает функции для генерации последовательности чисел – вроде range в Python. Она была бы очень полезна для циклов for…of и других ситуаций, когда нужен определенный диапазон значений.
Наверняка во время разработки вы активно пользуетесь консолью для тестирования и вывода данных. Для этого удобно применять метод JSON.stringify. Его третий параметр определяет количество пробелов для форматирования отступов. Кроме того есть второй параметр, который может быть полезен для обработки непримитивных типов данных – функций, символов и т.п., которые обычно игнорируются при сериализации.
В некоторых ситуациях требуется постоянно проверять наличие обновлений. Например, при загрузке файла, или для отображения прогресса обработки заказа. Для этого используется стратегия постоянного опроса (polling), при которой некоторая функция вызывается с определенным интервалом до получения нужного результата.
Раньше не существовало нативных функций для работы с наборами промисов, поэтому приходилось изобретать собственные решения. Но Promise API постоянно развивается, и теперь у нас есть замечательные методы allSettled, race and any, с которыми стоит познакомиться каждому разработчику.
Promise.all
Ожидает, когда выполнятся (resolve) все промисы в списке или хотя бы один из них будет отклонен (reject). Если не было ошибок, метод вернет массив с результатами выполнения промисов, сохранив их исходный порядок.
Promise.allSettled
Ожидает завершения всех промисов, независимо от их статуса выполнения. Возвращает массив с результатами. Каждый объект в этом массиве имеет поле status, которое может быть равно fullfilled или rejected. Если промис выполнился, то результат будет в поле value. Если же он был отклонен, то причина будет в поле reason.
Promise.any
Ожидает самого первого удачного завершения любого промиса из списка. Если ни один не завершился успешно, то вернет отклоненный промис.
Promise.rase
Ожидает самого первого завершения любого промиса из списка независимо от его статуса.
11. Перестановка элементов массива
Не то чтобы это была очень трудная задача, однако полезно знать, что в ES6 существует удобный способ ее решения.
12. Добавление ключа в объект по условию
Этот трюк очень полезен при работе с состояниями в React. Ключ добавляется (или не добавляется) в объект в зависимости от некоторого условия с помощью spread-оператора.
Условие задается с применением тернарного оператора. Если оно выполняется, вернется объект с ключами, которые нужно добавить в главный объект. Если не выполняется – пустой объект.
13. Использование переменных в качестве ключей объекта
Современный JavaScript также позволяет указывать строковые переменные в качестве ключей объекта. Для этого потребуются квадратные скобки:
Шаблонный литерал используется для явной интерполяции строкового значения, но можно обойтись и без него:
14. Проверка наличия ключа в объекте
Обычно для такой проверки нужен оператор in. Однако он учитывает не только собственные свойства объекта, но также и свойства всех его прототипов (как и цикл for...in). Это обычно не является желательным поведением. Лучше всего использовать проверку методом hasOwnProperty.
15. Удаление дублирующихся элементов массива
Избавиться от повторяющихся элементов массива очень просто – потребуется структура Set. Она отлично работает с разными типами данных и использует специфический алгоритм сравнения значений.
С объектами это, конечно, работать не будет, так как каждый объект уникален. Поэтому нужно вводить дополнительный фильтр:
16. break и continue в цикле forEach
Метод Array.forEach – очень удобная функциональная альтернатива обычному циклу for. Однако у него есть недостатки, например, отсутствие возможности прервать цикл в любой момент – по аналогии с оператором break.
Чтобы эмулировать это поведение, сохранив все преимущества, можно вызвать другой метод – Array.some. Он прекращает перебор элементов, если функция возвращает true. Используем этот трюк вместо break:
17. Деструктуризация с псевдонимами и дефолтными значениями
Деструктуризация – одна из самых мощных и удобных функций JavaScript, но синтаксис у нее довольно запутанный и сложный для запоминания. Поэтому повторяем еще раз, как задавать псевдонимы для названий полей и устанавливать значения по умолчанию:
18. Опциональные последовательности и нулевое слияние
Очень полезно при работе с неопределенными значениями. Оператор ?? возвращает правое значение только в том случае, если левое равно null или undefined. То есть он сохраняет все остальные falsy-значения, например, 0 или пустую строку.
В первом примере указанное поле существует, но его значение равно 0, что интерпретируется как falsy. Поэтому оператор || вернет правую часть – дефолтную строку.
Опциональные последовательности
Очень удобный прием для работы со структурами с большим уровнем вложенности.
В этом фрагменте кода происходит обращение к несуществующему полю объекта, поэтому выбрасывается ошибка. Чтобы избежать этого, приходится проверять проверку на каждом уровне вложенности:
Чем глубже структура объекта, тем сложнее становится конструкция и тем проще в ней ошибиться.
Оператор опциональных последовательностей ? позволяет существенно сократить это выражение:
19. Классы – это синтаксический сахар
Используя классы JavaScript, нельзя забывать, что это лишь синтаксический сахар над прототипами и функциями-конструкторами. Один из способов убедиться в этом – унаследовать класс от обычной функции-конструктора.
Этот сниппет является более «натуральным» и компиляторы лучше преобразуют и сжимают его.
20. Сложный конструктор
JavaScript не поддерживает множественное наследование, позволяя расширять лишь один класс. Однако при необходимости вы можете использовать композицию и подключить столько родительских классов, сколько нужно.
Всю эту логику можно поместить прямо в функцию-конструктор. Для расширения родительских классов используйте методы apply или call.
21. Итерирование всего
Для перебора элементов разных коллекций (Object, Array, Set, String и т. д.) приходится использовать разные методы. Было бы удобно объединить всю эту функциональность в один абстрактный метод.
Второй аргумент – callback – это функция для обработки элементов. Если она вернет true, цикл будет прерван (по аналогии с оператором break).
Вы можете убедиться, что функция получила все необходимые для работы аргументы, с помощью дефолтных параметров. Если параметр не передан, будет вызвана функция required, которая выбросит ошибку.
Иногда вам требуется какой-то глобальный для всей программу объект – синглтон. Можно долго спорить о том, насколько эта практика хороша, но полезно знать, как сделать это на JavaScript.
Используйте IIFE-выражение. Это функция, которая вызывается сразу же после создания. Внутри нее создается новый контекст выполнения, а значит, там можно легко изолировать все, что должно быть изолированным.
24. Глубокое копирование объектов
Для многоуровневого копирования объектов часто подключаются сторонние библиотеки (например, lodash). Однако эту задачу легко решить в JavaScript с помощью несложной рекурсивной функции. На каждом уровне она клонирует объекты с помощью их конструктора и копирует все поля.
Неизменяемость данных – важная часть функциональной парадигмы программирования. В JavaScript есть метод freeze, позволяющий "заморозить" объект, однако он действует лишь на один уровень в глубину. Для глубокой заморозки нужна рекурсия: