функция сама вызывается - при навешивании слушателя внутри другой функции

Пример здесь на codepen.io

Добавляю слушатель внутри функции document.addEventListener('click', closePopup), а он сразу исполняется с текущим event. :(

Помогите понять, почему? и как это исправить?

const button = document.querySelector('.button');
const popup = document.querySelector('.popup');

function closePopup(event) {
  console.log(event.target)
  if (!event.target.closest('.popup')) {
    removeClassActivePopup()
  }
}

function removeClassActivePopup() {
  button.classList.remove('button_active')
  popup.classList.remove('popup_visible')
  document.removeEventListener('click', closePopup)
}

function addClassActivePopup() {
  // если закомитить навешивание слушателя - работает
  // функция closePoupup вызывается при навешивании с текущим event и     закрывает popup
  document.addEventListener('click', closePopup)
  button.classList.add('button_active')
  popup.classList.add('popup_visible')
}

function showPopupSetting(e) {
  if (button.matches('.button_active')) {
    removeClassActivePopup()
  } else {
    addClassActivePopup()
  }
}

button.addEventListener('click', showPopupSetting)

Ответы (2 шт):

Автор решения: Igor

Вы добавляете обработчик события документу до того, как это событие "всплывет" до документа.

function clickDocument() {
  console.log('clickDocument');
}
function clickButton() {
  console.log('clickButton');
  document.addEventListener("click", clickDocument);
}

document.getElementById("test").addEventListener("click", clickButton);
<button id="test">Click</button>


function clickDocument() {
  console.log('clickDocument');
}
function clickButton(e) {
  e.stopPropagation();
  console.log('clickButton');
  document.addEventListener("click", clickDocument);
}

document.getElementById("test").addEventListener("click", clickButton);
<button id="test">Click</button>

→ Ссылка
Автор решения: Aziz Umarov

На самом деле проблема в 3 параметре addEventListener

useCapture

Если равно true, useCapture указывает, что пользователь желает начать захват. После инициализации захвата все события указанного типа будут отправлены в зарегистрированный listener перед отправкой в какой-либо EventTarget под ним в дереве DOM. События, восходящие вверх по дереву, не будут вызывать слушателей, которым назначено использовать захват. Смотрите DOM Level 3 Events для более детального объяснения. Значение useCapture по умолчанию равно false.

function clickDocument() {
  console.log('clickDocument');
}
function clickButton() {
  document.addEventListener("click", clickDocument, true);
  console.log('clickButton');  
}

document.getElementById("test").addEventListener("click", clickButton);
<button id="test">Click</button>

против

function clickDocument() {
  console.log('clickDocument');
}
function clickButton() {
  document.addEventListener("click", clickDocument);
  console.log('clickButton');  
}

document.getElementById("test").addEventListener("click", clickButton);
<button id="test">Click</button>

Обратите внимание на первый клик, до того как навешан был обработчик.

→ Ссылка