Замена конструкции switch на объектные литералы
Во многих языках программирования есть конструкция switch
– но стоит ли её применять?
Если вы JS-программист, вы постоянно работаете с объектами: создаёте, инициализируете и совершаете с ними разные манипуляции. Объекты очень гибкие — в javascript практически всё на них построено, и именно их я в последнее время использую вместо switch
.
Что такое конструкция switch?
Если вы ранее не использовали switch
или не очень понимаете, что данная конструкция делает, давайте разберёмся. Switch
последовательно сравнивает выражение со всеми указанными константами и выводит найденное соответствие, например, исполняемый блок кода.
Взглянем на типичное использование switch
:
|
|
Напоминает условную конструкцию else
и if
, но switch
сравнивает с одним значением в каждом случае case
нашей конструкции.
Когда в коде много условий else if
, вероятно, что-то не так – в подобных случаях целесообразнее использовать switch
. Вот пример злоупотребления else if
:
|
|
Данный вариант — слишком общий, допускает ошибки и крайне многословен (повторы). Он допускает и всякие хаки, тк можно сравнивать несколько значений в каждом else if
, например: else if (type === 'coke' && somethingElse !== 'apples')
. В таких ситуациях switch
был идеальным решением, хотя и приходилось не забывать добавлять оператор break
; в конце каждого случая case для предотвращения автоматического исполнения кода следующего case (частая ошибка switch).
Проблемы switch
В использовании switch
есть много неприятных моментов: процедурный поток управления, нестандартный синтактис блоков кода — в javascript стандартно используются фигурные скобки, в конструкции switch
– нет. В целом, синтаксис switch
– не лучший пример javascript. Мы вынуждены вручную добавлять break для каждого case, что может усложнить дальнейшую отладку ошибок, а если где-то забудем break, это спровоцирует ошибки в последующих случаях case. Дуглас Крокфорд не раз об этом писал и рассказывал, он рекомендует использовать switch
с осторожностью.
В javascript мы часто обращаемся к объектам для решения всевозможных задач, включая те, для которых нам бы и в голову не пришло использовать switch
. Так почему бы не использовать объектный литерал вместо switch
? Это сделает наш код более гибким, читаемым, поддерживаемым, и не нужно будет вручную добавлять к кейсам break! Также это упрощает работу новичкам, поскольку это стандартные объекты.
По мере увеличения количества case производительность объектов (хэш-таблиц) становится лучше, чем у конструкции switch
(где важна последовательность кэйсов). Объектный подход это поиск по хеш-таблицам, а конструкция switch
должна оценивать каждый case, пока не найдёт соответствие и break
.
Поиск по объектным литералам
Мы постоянно используем объекты как конструкторы или литералы, часто для операций поиска — получения значений свойств объекта.
Создадим простой объект, который возвращает только строковое значение:
|
|
Наш код на пару строк короче, чем пример со switch
, и, мне кажется, лучше читается. Упростим его, убрав дефолтное значение:
|
|
Однако, нам может понадобиться более сложное значение, чем строка, способное храниться в функции. Для краткости и простоты, я верну эти же строки в только что созданные функции:
|
|
Разница в том, что нам нужно вызвать функцию объекта:drinks[type]();
Такой код - легче поддерживать, приятнее читать. Простой объект. Можно забыть про break
и ошибки, связанные с его отсутствием в конце case.
В случае со switch
мы бы поместили его в функцию и return
значение, сделаем то же самое с объектом, превратив его в практичную функцию:
|
|
Всё отлично, но не учтён дефолтный случай. Это легко исправить:
|
|
Можно упростить нашу конструкцию else
и if
, используя в выражении оператор ||
«или»:
|
|
Мы поставили операции поиска по объекту ()
, что делает их выражением. И затем вызвали результат выражения. Если drinks [type]
не будет найден, вернётся drinks['default']
— элементарно!
Не обязательно всегда делать return
внутри функции, можем присвоить результат любой переменной и затем вызвать её.
|
|
- Это самые базовые примеры;
- Объектные литералы содержат функцию, которая возвращает строку;
Если вам нужна только строка, вы можете использовать строку как значение ключа — но иногда всё же логичнее использовать функции. Если вы используете и строки и функции, возможно, будет проще всегда использовать функции — для безопасного поиска параметра и дальнейшего вызова — мы ведь не хотим пытаться вызывать строку.
“Проскакивание” объектов
В случае со switch
мы можем позволить кейсу «проскочить» — когда к одному блоку кода применяется более одного случая case.
|
|
Мы позволяем coke
и pepsi
«проскочить» и не завершаем цикл switch
, поскольку не добавляем оператор break
. То же самое легко и более наглядно можно сделать с объектными литералами — это сделает наш код структурированным, читаемым и многократно используемым, а также убережёт от ошибкам.
|
|
####Выводы
Применение объектов даёт больший контроль над кодом, конструкция switch
– немного устарела, не изящна в синтаксисе и сложна в отладке ошибок. Объекты проще расширять, поддерживать и тестировать. Они привычны, поскольку являются основополагающим звеном Javascript, и мы используем их в работе каждый день для самых разных задач. Объектные литералы могут содержать функции и любые другие типы объектов, что делает их очень гибкими. У функций в литералах есть область действия (scope), поэтому мы можем вернуть замыкание из вызываемой родительской функции (в нашем случае getDrink
возвращает замыкание).
Комментарии и фидбэк можно найти на Reddit
По мотивам Todd Motto