Ошибка переключения календаря в JavaScript

Пусть мы хотим сделать стрелки для переключения календаря. В этом случае можно допустить ряд характерных ошибок. Давайте их рассмотрим.

Пусть у нас есть кнопки переключения и элемент, в который мы для простоты будем выводить не календарь, а просто год и название месяца:

html<button id="prev">prev</button>
<div id="elem"></div>
<button id="next">next</button>

Получим ссылки на наши элементы:

javascriptlet elem = document.querySelector('#elem');
let prev = document.querySelector('#prev');
let next = document.querySelector('#next');

Пусть у нас также есть функция, которая параметром принимает номер месяца и возвращает его название:

javascriptfunction getMonthName(month) {
  let names = [
    'янв', 'фев', 'мар', 'апр', 'май', 'июн',
    'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'
  ];
  
  return names[month];
}

Давайте по загрузке страницы получим текущий год и месяц:

javascriptlet date  = new Date;
let year  = date.getFullYear();
let month = date.getMonth();

Выведем в наш элемент год и название месяца (имитация календаря):

javascriptelem.textContent = year + ' ' + getMonthName(month);

Давайте теперь на переключатели навесим обработчики кликов:

javascriptprev.addEventListener('click', function() {
  // показываем предыдущий месяц
});

next.addEventListener('click', function() {
  // показываем следующий месяц
});

Рассмотрим теперь, какие ошибки можно допустить при реализации переключателей.

Ошибка первая

Пусть некоторый программист реализовал кнопки переключения месяцев:

javascriptnext.addEventListener('click', function() {
  elem.textContent = year + ' ' + getMonthName(month + 1);
});

prev.addEventListener('click', function() {
  elem.textContent = year + ' ' + getMonthName(month - 1);
});

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

Дело в том, что переменная month не изменяется внутри функций - к ее содержимому просто прибавляют единицу и результат отправляют в функцию getMonthName.

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

Исправим проблему:

javascriptnext.addEventListener('click', function() {
  month = month + 1;
  elem.textContent = year + ' ' + getMonthName(month);
});

prev.addEventListener('click', function() {
  month = month - 1;
  elem.textContent = year + ' ' + getMonthName(month);
});

Можно упростить:

javascriptnext.addEventListener('click', function() {
  elem.textContent = year + ' ' + getMonthName(++month);
});

prev.addEventListener('click', function() {
  elem.textContent = year + ' ' + getMonthName(--month);
});

Ошибка вторая

Часто забывают о том, что месяц должен изменяться в определенном диапазоне - от 0 до 11. При достижении границы диапазона мы должны менять год (вперед или назад), а месяц сбрасывать в начальное значение.

Сделаем это:

javascriptnext.addEventListener('click', function() {
  if (month === 11) {
    month = 0;
    year++;
  } else {
    month++;
  }
  
  elem.textContent = year + ' ' + getMonthName(month);
});

prev.addEventListener('click', function() {
  if (month === 0) {
    month = 11;
    year--;
  } else {
    month--;
  }
  
  elem.textContent = year + ' ' + getMonthName(month);
});