switch

Інструкція switch (перемикач) обчислює вираз, зіставляючи значення виразу з низкою пунктів case, і виконує інструкції після першого case, що дав збіг, поки не зустрінеться інструкція break. Відбудеться перехід до інструкції switch default, якщо жоден case не дасть збігу зі значенням виразу.

Спробуйте його в дії

Синтаксис

switch (expression) {
  case caseExpression1:
    інструкції
  case caseExpression2:
    інструкції
  // …
  ...
  case caseExpressionN:
    інструкції
  default:
    інструкції
}
expression (вираз)

Вираз, результат якого зіставляється зі кожним пунктом case.

case caseExpressionN (випадок) Необов'язкове

Пункт case, який зіставляється зі виразом expression. Якщо значення expression збігається зі значенням будь-якого caseExpressionN, то виконання починається від першої інструкції після відповідного пункту case, і триває або до кінця інструкції switch, або до першого ключового слова break (припинити).

default (усталено) Необов'язкове

Усталений пункт. Якщо вказаний — то його буде виконано в разі, якщо значення виразу expression не збігається зі жодним із пунктів case. Інструкція switch може мати лише один пункт default.

Опис

Спершу інструкція switch обчислює свій вираз. Далі вона шукає перший пункт case, чий вираз обчислюється до такого самого значення, як і те, що отримане від обчислення вхідного виразу (використовуючи порівняння на строгу рівність), і передає керування до цього пункту, виконуючи всі інструкції після нього.

Вирази пунктів обчислюються лише за потреби: якщо збіг вже знайдений, то подальші вирази пунктів case не будуть обчислені, навіть коли будуть відвідані по ходу провалювання.

switch (undefined) {
  case console.log(1):
  case console.log(2):
}
// Виводить лише 1

Якщо не дав збігу жоден пункт case, програма шукає необов'язковий усталений пункт, і якщо знаходить — передає керування йому, виконуючи інструкції після нього. Якщо усталеного пункту не знайдено — програма продовжує виконання з інструкції, яка йде наступною після кінця switch. Загальноприйнято ставити пункт default останнім, проте це не обов'язково. Інструкція switch може мати лише один пункт default; декілька пунктів default призведуть до SyntaxError.

Переривання та провалювання

Всередині тіла інструкції switch для раннього виходу з неї можна використовувати інструкцію break, наприклад, коли всі інструкції між двома пунктами case були виконані. Виконання продовжиться з першої інструкції після switch.

Якщо упустити break, то виконання продовжиться до наступного пункту case, навіть до пункту default, незалежно від того, чи дає значення виразу відповідного пункту збіг. Така поведінка зветься "провалюванням".

const foo = 0;
switch (foo) {
  case -1:
    console.log("від'ємна 1");
    break;
  case 0: // Значення foo дає збіг з цим критерієм; виконання почнеться звідси
    console.log(0);
  // Забули про break! Виконання провалиться далі
  case 1: // в 'case 0:' немає інструції break, тож цей пункт також буде виконаний
    console.log(1);
    break; // Зустріли break; переходу в 'case 2:' не буде
  case 2:
    console.log(2);
    break;
  default:
    console.log("default");
}
// Виводить 0 і 1

Інші інструкції контролю плину виконання, у відповідному контексті, також мають ефект виходу з інструкції switch. Наприклад, якщо інструкція switch міститься в функції, то інструкція return припиняє виконання тіла функції, а отже – виконання інструкції switch. Якщо інструкція switch міститься в циклі, то інструкція continue зупиняє інструкцію switch і переходить до наступної ітерації циклу.

Лексична область видимості

Пункти case і default подібні до міток: вони вказують місця, куди контроль плину виконання може перестрибнути. Проте вони не створюють самі по собі лексичних областей видимості (так само як не виконують автоматично виходу – як показано вище). Наприклад:

const action = "say_hello";
switch (action) {
  case "say_hello":
    const message = "привіт";
    console.log(message);
    break;
  case "say_hi":
    const message = "гей";
    console.log(message);
    break;
  default:
    console.log("Отримано порожню дію.");
}

Цей приклад виведе помилку "Uncaught SyntaxError: Identifier 'message' has already been declared", тому що перше оголошення const message = 'hello'; конфліктує з другим const message = 'hi';, навіть коли вони лежать в окремих пунктах випадку. По суті так відбувається через те, що обидва оголошення const лежать в межах однієї блокової області видимості, утвореної тілом switch.

Щоб це виправити, коли потрібно використати оголошення let чи const всередині пункту case, слід загорнути пункт у блок.

const action = "say_hello";
switch (action) {
  // додані фігурні дужки
  case "say_hello": {
    const message = "привіт";
    console.log(message);
    break;
  } // додані фігурні дужки
  case "say_hi": {
    const message = "гей";
    console.log(message);
    break;
  } // додані фігурні дужки
  default: {
    console.log("Отримано порожню дію.");
  } // додані фігурні дужки
}

Цей код тепер виведе в консоль привіт, як і повинен, без жодних помилок.

Приклади

Застосування switch

У наступному прикладі, якщо expr обчислюється до Банани — програма зіставляє значення зі випадком case 'Банани', і виконує відповідну інструкцію. Коли зустрічається break, програма виходить з інструкції switch і виконує наступну за switch інструкцію. Якби break був упущений, то також виконалися б інструкції для пункту case 'Вишні'.

switch (expr) {
  case "Помаранчі":
    console.log("Помаранчі — по $0.59 за кіло.");
    break;
  case "Яблука":
    console.log("Яблука — по $0.32 за кіло.");
    break;
  case "Банани":
    console.log("Банани — по $0.48 за кіло.");
    break;
  case "Вишні":
    console.log("Вишні — по $3.00 за кіло.");
    break;
  case "Манго":
  case "Папайя":
    console.log("Манго та папайя — по $2.79 за кіло.");
    break;
  default:
    console.log(`Вибачте, у нас закінчились ${expr}.`);
}

console.log("Чи є щось іще, що ми могли б вам запропонувати?");

Розташування усталеного пункту між двома пунктами випадків

Якщо не знайдено збігу, то виконання почнеться від пункту default, виконуючи всі інструкції після нього.

const foo = 5;
switch (foo) {
  case 2:
    console.log(2);
    break; // програма зустрічає оцей `break`, тож виконання не буде продовжуватись всередину 'default:'
  default:
    console.log("default");
  // провалювання
  case 1:
    console.log("1");
}

Це так само працює, якщо поставити default перед всіма іншими пунктами case.

Користь від провалювання

Цей метод заснований на тому факті, що за відсутності break під пунктом case виконання продовжиться наступним пунктом case, незалежно від того, чи відповідає він критерію.

Нижче – приклад послідовної інструкції case з однією операцією, де чотири різні значення працюють цілком однаково.

const Animal = "Жираф";
switch (Animal) {
  case "Корова":
  case "Жираф":
  case "Собака":
  case "Кнур":
    console.log("Ця тварина не вимерла.");
    break;
  case "Динозавр":
  default:
    console.log("Ця тварина вимерла.");
}

Нижче – приклад послідовної інструкції case із багатьма операціями, в якому, залежно від переданого цілого числа, можна отримати різний вивід. Цей приклад демонструє, що виконання інструкцій відбувається в порядку, в якому розміщені пункти, і цей порядок не обов'язково повинен відповідати числовій послідовності. У JavaScript можна навіть домішувати також і означення рядків у ці інструкції case.

const foo = 1;
let output = "Вивід: ";
switch (foo) {
  case 0:
    output += "Отже, ";
  case 1:
    output += "Як ";
    output += "Звучить ";
  case 2:
    output += "Твоє ";
  case 3:
    output += "Ім'я";
  case 4:
    output += "?";
    console.log(output);
    break;
  case 5:
    output += "!";
    console.log(output);
    break;
  default:
    console.log("Будь ласка, оберіть число від 0 до 5!");
}

Вивід цього прикладу матиме такий вигляд:

Значення Друкує текст
foo is NaN or not 1, 2, 3, 4, 5, or 0 Будь ласка, оберіть число від 0 до 5!
0 Вивід: Отже, Як Звучить Твоє Ім'я?
1 Вивід: Як Звучить Твоє Ім'я?
2 Вивід: Твоє Ім'я?
3 Вивід: Ім'я?
4 Вивід: ?
5 Вивід: !

Альтернатива ланцюжкам if...else

Нерідко доводиться робити ряд перевірок if...else.

if ("fetch" in globalThis) {
  // Отримання ресурсу за допомогою fetch
} else if ("XMLHttpRequest" in globalThis) {
  // Отримання ресурсу за допомогою XMLHttpRequest
} else {
  // Отримання ресурсу за допомогою певної самописної логіки AJAX
}

Цей патерн не робить послідовності порівнянь ===, але його все одно можна перетворити на конструкцію switch.

switch (true) {
  case "fetch" in globalThis:
    // Отримання ресурсу за допомогою fetch
    break;
  case "XMLHttpRequest" in globalThis:
    // Отримання ресурсу за допомогою XMLHttpRequest
    break;
  default:
    // Отримання ресурсу за допомогою певної самописної логіки AJAX
    break;
}

Патерн switch (true) як альтернатива if...else є особливо корисним, коли треба скористатися логікою провалювання.

switch (true) {
  case isSquare(shape):
    console.log("Ця фігура є квадратом.");
  // Провалювання, оскільки квадрат також є прямокутником!
  case isRectangle(shape):
    console.log("Ця фігура є прямокутником.");
  case isQuadrilateral(shape):
    console.log("Ця фігура є чотирикутником.");
    break;
  case isCircle(shape):
    console.log("Ця фігура є колом.");
    break;
}

Специфікації

Сумісність із браузерами

desktop mobile server
Chrome Edge Firefox Internet Explorer Opera Safari WebView Android Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet Deno Node.js
switch
Chrome Full support 1
Edge Full support 12
Firefox Full support 1
Internet Explorer Full support 4
Opera Full support 4
Safari Full support 1
WebView Android Full support 1
Chrome Android Full support 18
Firefox for Android Full support 4
Opera Android Full support 10.1
Safari on iOS Full support 1
Samsung Internet Full support 1.0
Deno Full support 1.0
Node.js Full support 0.10.0

Дивіться також