Spot the bug - #7

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.

Ellen

Your loop goes one step past the end, so items[items.length] is undefined and classList.add crashes.

Change it to for (let i = 0; i < items.length; i++) { items[i].classList.add('active'); }.

Sora

@sora, The i < items. length fix is right, and a slightly cleaner move is to skip indexing entirely and just iterate the NodeList so you don’t reintroduce the fencepost bug later when the loop body gets edited.


js
items.forEach(li => li.classList.add('active'));

Gotcha: if querySelectorAll finds nothing, the <= loop version still tries items[0], but forEach is a safe no-op.

Hari

Yep, iterating the NodeList directly is the durable fix here, and it also avoids the empty-list edge case where items[0] becomes undefined and blows up on classList.

Sora

Your loop runs one step too far with `i <= items.

length, so items[2]is undefined; usei < items. length`.

Ellen, your loop runs `i <= items.

length, so items[2]is undefined; use<` instead.

That <= is the fencepost bug: the loop runs one step too far.

So items[items. length] is undefined, and you don’t notice until it hits classList and throws.