Клавиша / esc

switch

Выполняем код при совпадении значения переменной с ожидаемым значением.

Время чтения: меньше 5 мин

Кратко

Скопировано

Управляющая конструкция switch позволяет выполнять различные блоки кода, в зависимости от значения переменной.

Похож на if...else, но решает более узкую задачу.

Как пишется

Скопировано
        
          
          switch (имя_переменной_значение_которой_сравниваем) {  case значение:    // код    break}
          switch (имя_переменной_значение_которой_сравниваем) {
  case значение:
    // код
    break
}

        
        
          
        
      

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

Пример приветствия пользователя в зависимости от статуса:

        
          
          switch (membershipStatus) {  case 'vip':    // выполнится, если в переменной membershipStatus хранится строка 'vip'    console.log('Приветствуем вас, ваше великолепие!')    console.log('рады вас видеть!')    break  case 'diamond':    console.log('Здравствуйте, бриллиантовый клиент!')    break  case 'gold':    console.log('Привет, золотой мой!')    break  default:    // выполнится, если ни один другой случай не сработал    console.log('Прив')    break}
          switch (membershipStatus) {
  case 'vip':
    // выполнится, если в переменной membershipStatus хранится строка 'vip'
    console.log('Приветствуем вас, ваше великолепие!')
    console.log('рады вас видеть!')
    break
  case 'diamond':
    console.log('Здравствуйте, бриллиантовый клиент!')
    break
  case 'gold':
    console.log('Привет, золотой мой!')
    break
  default:
    // выполнится, если ни один другой случай не сработал
    console.log('Прив')
    break
}

        
        
          
        
      

Как понять

Скопировано

В программировании часто встречается задача выполнения разного кода в зависимости от какого-либо условия. Обычно, такие задачи решают с помощью конструкции if...else.

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

Такую задачу тоже можно решить с помощью if..else:

        
          
          let discountif (memberStatus === 'vip') {  discount = 0.25} else if (memberStatus === 'diamond') {  discount = 0.2} else if (memberStatus === 'gold' || memberStatus === 'silver') {  // скидка 10% пользователям статуса золотой и серебряный  discount = 0.1} else {  discount = 0}
          let discount
if (memberStatus === 'vip') {
  discount = 0.25
} else if (memberStatus === 'diamond') {
  discount = 0.2
} else if (memberStatus === 'gold' || memberStatus === 'silver') {
  // скидка 10% пользователям статуса золотой и серебряный
  discount = 0.1
} else {
  discount = 0
}

        
        
          
        
      

Код выше работает, но выглядит избыточно — в нем очень много сравнений с использованием memberStatus. Конструкция switch решает такую задачу меньшим объёмом кода:

        
          
          let discountswitch (memberStatus) {  case 'vip':    discount = 0.25    break  case 'diamond':    discount = 0.2    break  case 'gold':  case 'silver':    // можно написать несколько кейсов и связать с одним блоком    discount = 0.1    break  default:    discount = 0    break}
          let discount
switch (memberStatus) {
  case 'vip':
    discount = 0.25
    break
  case 'diamond':
    discount = 0.2
    break
  case 'gold':
  case 'silver':
    // можно написать несколько кейсов и связать с одним блоком
    discount = 0.1
    break
  default:
    discount = 0
    break
}

        
        
          
        
      

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

Внутри кейса пишется список команд, которые нужно выполнить. Список команд завершается оператором break.

Существует необязательный кейс default, который срабатывает, если ни одно значение не подошло.

Что будет, если не поставить break?

Скопировано

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

Сравните:

Показан код, выполняемый только между текущими  и , и код, выполняемый от  до , даже если он вне текущего кейса

Выполняется весь код от текущего case до следующего break, даже если он вне текущего кейса.

В коде появился баг — значение для бриллиантового уровня будет установлено в 0.1 вместо 0.2.

На практике

Скопировано

Артур Бэйлис Ли советует

Скопировано

Есть когнитивное искажение, называемое «Закон инструмента»:

Если из инструментов у вас только молоток, всё вокруг кажется гвоздями

Так и switch часто превращается в такой молоток. Конечно, у switch есть свои преимущества: можно использовать разом несколько case, в условиях можно написать различную логику и прочее.

        
          
          function greet(role) {  switch (role) {    case 'admin':    case 'moder':      return 'Приветствую, смотритель порядка'    case 'user':      trackUserVisit()      return 'Здравствуй, пользователь'    case 'guest':      return 'Здравствуй, гость'    default:      return 'Привет, некто'  }}
          function greet(role) {
  switch (role) {
    case 'admin':
    case 'moder':
      return 'Приветствую, смотритель порядка'
    case 'user':
      trackUserVisit()
      return 'Здравствуй, пользователь'
    case 'guest':
      return 'Здравствуй, гость'
    default:
      return 'Привет, некто'
  }
}

        
        
          
        
      

Однако часто нам нужно просто соотнести одно значение с другим. И в таких случаях лучше завести словарь:

        
          
          const roleToGreeting = {  admin: 'Приветствую, босс',  moder: 'Приветствую, смотритель порядка',  user: 'Здравствуй, пользователь',  guest: 'Здравствуй, гость',}const greetings = (role) => roleToGreeting[role] ?? 'Привет, некто'
          const roleToGreeting = {
  admin: 'Приветствую, босс',
  moder: 'Приветствую, смотритель порядка',
  user: 'Здравствуй, пользователь',
  guest: 'Здравствуй, гость',
}

const greetings = (role) => roleToGreeting[role] ?? 'Привет, некто'

        
        
          
        
      

Есть ещё шаблон switch (true), который якобы сокращает if...else if...else:

        
          
          function getCategoryByAge(age) {  switch (true) {    case (age >= 0 && age <= 12):      return "Child"    case (age >= 13 && age <= 19):      return "Teenager"    case (age >= 20 && age <= 35):      return "Young Adult"    case (age >= 36 && age <= 55):      return "Adult"    case (age > 55):      return "Senior"    default:      return "Invalid age"  }}
          function getCategoryByAge(age) {
  switch (true) {
    case (age >= 0 && age <= 12):
      return "Child"
    case (age >= 13 && age <= 19):
      return "Teenager"
    case (age >= 20 && age <= 35):
      return "Young Adult"
    case (age >= 36 && age <= 55):
      return "Adult"
    case (age > 55):
      return "Senior"
    default:
      return "Invalid age"
  }
}

        
        
          
        
      

Использование switch (true) является спорным вопросом и выглядит скорее как хак, нежели задуманный сценарий использования языка. Также учтите, что вашим коллегам эта конструкция может быть непривычна, в отличие от обычных условий, которые понятны всем. Сторонники switch (true) утверждают, что он позволяет сократить код, но пример выше напротив будет более лаконичным без него:

        
          
          function getCategoryByAge(age) {  if (age >= 0 && age <= 12) return "Child"  if (age >= 13 && age <= 19) return "Teenager"  if (age >= 20 && age <= 35) return "Young Adult"  if (age >= 36 && age <= 55) return "Adult"  if (age > 55) return "Senior"  return "Invalid age"}
          function getCategoryByAge(age) {
  if (age >= 0 && age <= 12) return "Child"
  if (age >= 13 && age <= 19) return "Teenager"
  if (age >= 20 && age <= 35) return "Young Adult"
  if (age >= 36 && age <= 55) return "Adult"
  if (age > 55) return "Senior"

  return "Invalid age"
}

        
        
          
        
      

Николай Лопин советует

Скопировано

🛠 Обязательно ставьте break в конце каждого кейса. Такой код будет хорошо читаться и не приведёт к неожиданным багам.

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

🛠 Если в вашем свитче меньше трёх кейсов, то if...else будет читаться проще.

🛠 Если внутри кейса нужно создать переменную, то придётся добавить фигурные скобки, иначе JavaScript упадёт с ошибкой:

        
          
          switch (variable) {  case 5: {    const myVar = 'Hello'  }}
          switch (variable) {
  case 5: {
    const myVar = 'Hello'
  }
}