dr.Brain

doctor Brain

мир глазами веб-разработчика

JavaScript: объектные литералы вместо if и switch

пишем понятные условия с помощью объектных литералов в JavaScript

dr.Brain

время чтения 3 мин.

Photo by Timo Volz on Unsplash

Сложные условия в JavaScript ведут к появлению запутанного и плохо читаемого кода. Длинный список инструкций сравнения if/else или switch склонен к быстрому, постоянному и практически неконтролируемому росту.

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

Для примера рассмотрим функцию, которая получает в качестве параметра фразу и возвращает в результате рифмующееся с этой фразой слово.

Прибегнув к инструкции if/else, мы получим следующий код:

function getTranslation(rhyme) {
  if (rhyme.toLowerCase() === "apples and pears") {
    return "Stairs";
  } else if (rhyme.toLowerCase() === "hampstead heath") {
    return "Teeth";
  } else if (rhyme.toLowerCase() === "loaf of bread") {
    return "Head";
  } else if (rhyme.toLowerCase() === "pork pies") {
    return "Lies";
  } else if (rhyme.toLowerCase() === "whistle and flute") {
    return "Suit";
  }

  return "Rhyme not found";
}

Получается не очень хороший пример. Код читается достаточно плохо. К тому же, для каждого условия приходится повторять метод toLowerCase(). Такого повторения можно избежать, приведя фразу к нижнему регистру в самом начале функции или воспользовавшись инструкцией сравнения switch:

function getTranslation(rhyme) {
  switch (rhyme.toLowerCase()) {
    case "apples and pears":
      return "Stairs";
    case "hampstead heath":
      return "Teeth";
    case "loaf of bread":
      return "Head";
    case "pork pies":
      return "Lies";
    case "whistle and flute":
      return "Suit";
    default:
      return "Rhyme not found";
  }
}

Теперь метод toLowerCase() встречается в коде только один раз, но синтаксис все еще далек от идеального. Еще одни негативным моментом является то, что инструкция switch в значительной степень подвержена вероятности возникновения ошибок из-за невнимательности разработчика. Например, в коде есть более сложные условия, а это значит, что программист может пропустить оператор break и разрушить всю логику какой-то части проекта.

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

function getTranslationMap(rhyme) {
  const rhymes = {
    "apples and pears": "Stairs",
    "hampstead heath": "Teeth",
    "loaf of bread": "Head",
    "pork pies": "Lies",
    "whistle and flute": "Suit",
  };
  
  return rhymes[rhyme.toLowerCase()] ?? "Rhyme not found";
}

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

В последней строке функции ?? "Rhyme not found" мы видим оператор нулевого слияния ?? (nullish coalescing), который, согласно определению, возвращает значение правого операнда в тех случаях, когда значение левого операнда равно null или undefined (но не false или 0). Таким образом, если условие не найдется, функция возвратит в результате фразу “Rhyme not found”.

Тот факт, что правый оператор возвращается только при наличии null и undefined с левой стороны выражения, очень важен. Эта особенность позволяет в штатном порядке возвращать ответ false и 0:

function stringToBool(str) {
  const boolStrings = {
    "true": true,
    "false": false,
  };

  return boolStrings[str] ?? "String is not a boolean value";
}

Конечно, этот пример не имеет практического применения, но он хорошо иллюстрирует возможности оператора нулевого слияния.

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

function calculate(num1, num2, action) {
  const actions = {
    add: (a, b) => a + b,
    subtract: (a, b) => a - b,
    multiply: (a, b) => a * b,
    divide: (a, b) => a / b,
  };

  return actions[action]?.(num1, num2) ?? "Calculation is not recognised";
}

Так, пример, приведенный выше, показывает, что мы можем выбрать типа вычисления, указать исходные значения и получить ответ в значении ключа объекта. Оператор опциональной последовательности ?. (optional chaining) используется только тогда, когда ответ определен, Для всех остальных случаев с помощью оператора нулевого слияния установлен ответ по умолчанию.

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


Спасибо за внимание.


Перевод статьи Jack Taylor “Don’t Use If-Else and Switch in JavaScript, Use Object Literals”.

Новые публикации

Далее

Категории

О нас

Frontend & Backend. Статьи, обзоры, заметки, код, уроки.