И ifs, и switches предназначены для выбора одного из немногих возможных фрагментов кода.

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

Некоторые языки, такие как Elm, очень строгие. Когда есть if, должно быть else. Когда есть case (имя вяза для switch выражения), он должен перечислять все возможные значения. Другие языки, например JavaScript, этого не требуют.

Также бывают случаи, когда switch быстрее, чем if.

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

If выбирает один фрагмент кода, когда значение true (или истинное значение), и другой, когда оно false (или ложное). Всегда есть только два проверяемых значения: true и false.

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

Давайте посмотрим на очень простой пример. Речь идет о загрузке чего-либо по сети. Этот код ifs побудил меня написать:

if (state.isLoaded) {
  // ...
} else {
  // ...
  if (state.errorOccurred) {
    // ...
  } else {
    // ...
  }
  // ...
}

Если бы я писал это на TypeScript, было бы очень заманчиво определить тип state следующим образом:

let state: {isLoaded: boolean, errorOccurred: boolean};

Хотя на первый взгляд это может показаться законным, это не так.

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

state = {isLoaded: true, errorOccurred: true};

Правильный тип выглядит примерно так:

let state:
    {isLoaded: true, errorOccurred: false}
    | {isLoaded: false, errorOccurred: true}
    | {isLoaded: false, errorOccurred: false}
;

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

let state: "loading" | "loaded" | "error";

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

switch (state) {
  case "loading":
    // ...
    break;
  case "error":
    // ...
    break;
  case "loaded":
    // ...
    break;
}

Как бы мало смысла в этом не было, мы можем согнуть if, чтобы он выглядел как switch, и наоборот:

if (state === "loading") {
  // ...
} else if (state === "error") {
  // ...
} else if (state === "loaded") {
  // ...
}
switch (state.isLoaded) {
  case true:
    // ...
    break;
  case false:
    // ...
    switch (state.errorOccurred) {
      case true:
        // ...
        break;
      case false:
        // ...
        break;
    }
    // ...
    break;
}

Здесь становится ясно, что разница между if и switch не в синтаксисе. Речь идет о ментальной модели. Хочу ли я принимать решения на основе того, является ли какое-то выражение истинным, или я хочу обнаружить все возможные состояния и назначить им различные варианты поведения?

Что действительно интересно, так это то, что процесс выявления состояния - это только первый шаг. Хотя switches ясно представляют все состояния, они скрывают изменения состояния.

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

Первоначально опубликовано на lukaszmakuch.pl 5 июня 2018 г.

✉️ Подпишитесь на рассылку еженедельно Email Blast от CodeBurst 🐦 Подпишитесь на CodeBurst на Twitter , просмотрите 🗺️ Дорожная карта веб-разработчиков на 2018 год и 🕸️ Изучите веб-разработку с полным стеком .