The for...in Loop
In short: for (const key in object) walks an object's enumerable
keys — the labels, not what's inside the drawers. On a plain object
that's exactly what you want. On an array, the keys are the string
indices "0", "1", "2" — it often looks like it works, but it also
visits any inherited enumerable property, which makes it the wrong
tool for arrays. Use for...of or a plain for loop there instead.

Printing every field of a song
for...in is built for exactly this: visiting an object's own properties
without knowing their names in advance.
Each lap hands you a key — "title", "plays", "liked" — and
song[key] reads the value that goes with it. This is the natural way to
print or process an object whose exact shape you don't know ahead of time.
The array trap: keys are strings, not numbers
Run the same pattern on an array and it looks fine — until you check the type:
The keys are "0" and "1" — strings, not numbers. songs["0"]
still works, because JavaScript converts the string back for you, but any
arithmetic on index (like index + 1) would join text instead of
adding, the same trap from the type-casting lessons.
Inherited keys show up too
The deeper reason for...in is risky on arrays: it walks every
enumerable property, including ones inherited from further up the chain.
The first loop sees both "title" (the object's own) and "genre"
(inherited from base) — a surprise if you only expected extended's own
fields. Object.hasOwn(extended, key) filters to just the object's own
properties, which is usually what you actually want.
Quick practice
What does for (const key in { a: 1, b: 2 }) hand you on each lap?
For const arr = ["x", "y"], what type is the index in for (const index in arr)?
Why is for...in considered risky for looping over arrays?
