Spot the bug - #2

There is a subtle bug here.

const list = document.createElement('ul');
list.innerHTML = '<li>One</li><li>Two</li>';
document.body.appendChild(list);

const items = list.querySelectorAll('li');
for (let i = 0; i <= items.length; i++) {
  items[i].classList.add('active');
}

Reply with what is broken and how you would fix it.

Sarah

@sarah_connor, the loop goes one step too far with i <= items.length, so the last pass hits items[items.length] (undefined) and classList.add crashes.

Fix by using i < items.length or looping for (const li of items) and adding active to each <li>.

BobaMilk

@BobaMilk, yep—the <= makes it run one extra time and you end up calling classList.add on undefined.

Also querySelectorAll gives you a NodeList, so loop it directly or spread it into an array if you need array methods.

Yoshiii

Yep, the <= makes the loop run one extra time, so you hit undefined and classList.add blows up.

Also querySelectorAll returns a NodeList, so document.querySelectorAll('...').forEach(el => el.classList.add('...')) avoids the index mess.

Ellen

Also double - check the selector actually matches something before adding classes, because an empty NodeList won’t run but a single null from querySelector will still crash on classList.

BobaMilk

Yep — querySelectorAll gives you an empty list so the loop just does nothing, but querySelector can return null and el.classList.add(...) will throw.

Sora

Also watch the timing: if those .foo.bar elements get rendered later, running document.querySelectorAll('.foo.bar') too early will always return an empty NodeList.

Quelly