Skip to main content

Різниця між event.target та event.currenttarget у JavaScript

event.target - це елемент, на якому подія фактично виникла. event.currentTarget - це елемент, до якого прикріплений обробник події.

Теорія

TL;DR

  • event.target - звідки подія прийшла (кнопка, на яку натиснули всередині div).
  • event.currentTarget - де живе твій addEventListener (сам div).
  • Під час бабблінгу target не змінюється; currentTarget оновлюється на кожному обробнику.
  • Треба знати, що саме натиснули? Бери target. Треба елемент з обробником? Бери currentTarget.
  • Для делегування подій (event delegation) на динамічних списках - target.

Швидкий приклад

html
<div id="parent" style="padding: 20px; background: lightblue;"> <button id="child">Click me</button> </div>
javascript
const parent = document.getElementById('parent'); parent.addEventListener('click', (event) => { console.log(event.target.id); // "child" — натиснули кнопку console.log(event.currentTarget.id); // "parent" — обробник тут });

Натискаєш кнопку: target вказує на кнопку, currentTarget на div. Обробник на div, але клік стався на кнопці всередині нього.

Головна різниця

Коли подія піднімається по DOM (бабблінг), event.target залишається прив'язаним до елемента, де подія виникла. А event.currentTarget оновлюється на кожному кроці і завжди відображає елемент, чий обробник зараз виконується. Якщо у тебе вкладені div-и з обробниками на кожному, target буде однаковим у всіх, а currentTarget у кожного свій.

Коли що використовувати

  • Динамічні дочірні елементи (делегування подій): використовуй target. Прикріплюєш один обробник на батьківський <ul> і перевіряєш e.target, щоб знайти конкретний <li>. Працює навіть для елементів, доданих після завантаження сторінки.
  • Власний елемент обробника: використовуй currentTarget. Перемикання класу або читання розмірів елемента, до якого прикріплений обробник.
  • Більше 10 динамічних дочірніх елементів: делегування через target рятує від прикріплення окремих обробників до кожного.
  • Один елемент з обробником: currentTarget передбачуваний і не потребує додаткових перевірок.

Таблиця порівняння

event.targetevent.currentTarget
Вказує наЕлемент, де виникла подіяЕлемент з прикріпленим обробником
Під час бабблінгуНе змінюєтьсяОновлюється на кожному обробнику
Дорівнює this?Не завждиТак (у звичайних функціях)
Використовується дляДелегування, визначення джерелаРобота з елементом-власником обробника

Як браузер встановлює ці значення

Браузер відправляє події згідно специфікації DOM Level 2/3: фаза захоплення (capture) вниз, фаза цілі (target), фаза бабблінгу вгору. Кожного разу, коли виконується обробник, рушій встановлює currentTarget на елемент, який зареєстрував цей конкретний обробник. target встановлюється один раз при відправці і більше не змінюється. Тому після stopPropagation() target все одно залишається початковим елементом.

Типові помилки

Помилка: стилізувати target, коли потрібен елемент обробника

javascript
// Обробник на div; користувач натискає вкладений img всередині div elem.addEventListener('click', (e) => { e.target.style.background = 'red'; // Фарбує img, а не div });

Виправлення: e.currentTarget.style.background = 'red'.

Помилка: перемикати клас через target без перевірки

javascript
parent.addEventListener('click', (e) => { e.target.classList.toggle('active'); // Перемикає на будь-якому дочірньому: span, p, img... });

Виправлення: додай перевірку. if (e.target.matches('button')) e.currentTarget.classList.toggle('active').

Помилка: вважати що target === currentTarget завжди

Вони рівні тільки коли натискаєш безпосередньо на елемент з обробником. Щойно клік потрапляє на дочірній елемент, вони розходяться. Це частий баг в обробниках закриття tooltip, де клік на span всередині wrapper закриває сам tooltip - бо обробник перевіряє e.target замість e.currentTarget.

Де зустрічається

  • React: SyntheticEvent.target для делегування форм (читання e.target.value у спільному onChange). currentTarget для доступу до самого елемента форми.
  • Vue: $event.target всередині v-on для динамічного контенту слотів.
  • Vanilla delegation: один обробник на таблиці, e.target.closest('tr') щоб отримати натиснутий рядок.
  • Міграція з jQuery: патерни $(event.target).closest() перекладаються на vanilla через e.target.closest().

Питання на співбесіді

Q: Що відбувається з target і currentTarget у фазі захоплення (capture)?
A: Обидва встановлюються і під час capture. currentTarget відповідає елементу, що перехоплює, а target все одно залишається початковим джерелом події.

Q: Чи змінює stopPropagation() значення target?
A: Ні. target фіксується при відправці події. stopPropagation() тільки зупиняє переміщення події до наступного елемента в ланцюжку.

Q: Чому this у звичайній функції-обробнику дорівнює currentTarget?
A: Браузер встановлює this рівним currentTarget при виклику обробника. Стрілкові функції не мають власного this, тому там цей механізм не працює.

Q: Що буде, якщо натиснути безпосередньо на елемент з обробником, без вкладених дочірніх?
A: target === currentTarget. Вони розходяться тільки коли клік відбувається на дочірньому елементі.

Q: У React Portal, на що вказує target?
A: target вказує на дочірній елемент порталу. React перерозподіляє синтетичні події через дерево React-компонентів, тому делегування працює навіть через межу порталу.

Приклади

Делегування подій на динамічному списку

javascript
const list = document.getElementById('list'); // Один обробник покриває всі елементи, включно з тими, що додаються пізніше list.addEventListener('click', (e) => { if (e.target.tagName === 'LI') { console.log('Натиснуто:', e.target.textContent); e.target.classList.toggle('selected'); } // e.currentTarget завжди є елементом #list }); // Цей новий елемент одразу працює — без додаткового обробника const newItem = document.createElement('li'); newItem.textContent = 'Новий елемент'; list.appendChild(newItem);

Один обробник на батьківському елементі охоплює всі пункти, поточні і майбутні. e.target повідомляє, який конкретний пункт натиснули; e.currentTarget завжди вказує на список.

Форма зі спільним обробником, який використовує обидві властивості

javascript
const form = document.getElementById('signup-form'); form.addEventListener('change', (e) => { const field = e.target; // Яке поле змінилось const formEl = e.currentTarget; // Елемент форми console.log('Назва поля:', field.name); console.log('Нове значення:', field.value); // Перевірка всієї форми через елемент форми const allInputs = formEl.querySelectorAll('input'); const allFilled = [...allInputs].every(i => i.value.trim() !== ''); formEl.querySelector('#submit').disabled = !allFilled; });

e.target визначає, яке поле змінилось. e.currentTarget дає доступ до всієї форми для повторної перевірки. Обидві властивості виконують різну роботу в одному обробнику.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?