$lis = document.getElementsByTagName('li'); for (let i = 0; i < $lis.length; i++) { $li = $lis[i]; $span = $li.getElementsByTagName('span')[0]; $button = $li.getElementsByTagName('button')[0]; $button.addEventListener('click', $li.remove); } <ul> <li> <span>1</span> <button>x</button> </li> </ul> En la última línea, estoy usando el método Element.remove() , pero en lugar de eliminar <li> , elimina <button> .
Explícame, por favor, por qué. Siento que hay algo con this que sucede, pero quiero entender esto completamente, no solo sentirlo .
PD: También entiendo que puedo resolver esto envolviendo $li.remove en una función anónima, pero el objetivo de mi pregunta es comprender el comportamiento descrito, no solo para resolver el problema. Gracias.
En esta línea $button.addEventListener('click', $li.remove); está pasando el método de remove de $li como su controlador de clics. La naturaleza de los controladores de clics (y otros controladores de eventos de usuario) es volver a vincular this en la función del controlador al elemento al que adjunta el oyente, por lo que lo que realmente sucede es
$li.remove.call($button) Puedes arreglarlo usando bind :
$button.addEventListener('click', $li.remove.bind($li))Nota al margen:
Reemplace la HTMLCollection en vivo document.getElementsByTagName('li') con una NodeList estática usando document.querySelectorAll('li') .
Eliminar un elemento del DOM también lo eliminará inmediatamente de cualquier HTMLCollection de la que sea parte, estropeando sus índices.
Es porque el botón porque el nuevo contexto o this con el que se llama a Element.remove() . Una función anyonmous, o más exactamente, una función de flecha, usa el ámbito léxico en el que se declara como contexto, por eso funciona.
Entonces button.addEventListener('click', elementX.remove) en realidad toma la función prototipo remove y la llama con el botón como contexto o, en otras palabras, la bind al botón.
Una forma de demostrar que la vinculación puede funcionar es vincular remove al elemento y luego agregarlo como el controlador de eventos $li.remove.bind($li) esta manera, independientemente del contexto implícito, lo hemos establecido explícitamente en $li .
$lis = document.getElementsByTagName('li'); for (let i = 0; i < $lis.length; i++) { $li = $lis[i]; $span = $li.getElementsByTagName('span')[0]; $button = $li.getElementsByTagName('button')[0]; let remove = $li.remove.bind($li) $button.addEventListener('click', remove); } <ul> <li> <span>1</span> <button>x</button> </li> </ul>