switch
Інструкція switch
(перемикач) обчислює вираз, зіставляючи значення виразу з низкою пунктів case
, і виконує інструкції після першого case
, що дав збіг, поки не зустрінеться інструкція break
. Відбудеться перехід до інструкції switch
default
, якщо жоден case
не дасть збігу зі значенням виразу.
Спробуйте його в дії
Синтаксис
switch (expression) {
case caseExpression1:
інструкції
case caseExpression2:
інструкції
// …
...
case caseExpressionN:
інструкції
default:
інструкції
}
expression
(вираз)Вираз, результат якого зіставляється зі кожним пунктом
case
.caseExpressionN
(вираз випадку № N) Необов'язковеПункт
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 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
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 |