JavaScript60 min total · 16 parts
JavaScript Array and Object Methods Cheat Sheet
Part 5 of 16 · ~2 min
Iterating Arrays
candidates.forEach((candidate, index) => {
sendReminderEmail(candidate, index);
});
.forEach() calls your function once for every element and hands nothing back — its return value is always undefined, regardless of what the callback itself does. Reach for it expecting a transformed array in return — the way .map() would give you one — and you'll come away empty-handed, because that was never its job:
// Nothing useful comes out of this, and it doesn't stop at Sam either:
const activeOnly = candidates.forEach(c => { if (c.status !== "active") return; });
console.log(activeOnly); // undefined
// for...of actually can be stopped early:
for (const c of candidates) {
if (c.status === "withdrawn") break;
console.log(c.name);
}
for...of steps through values one at a time and doesn't care what kind of iterable it's handed — an array, a string, a Map, a Set, or anything else that knows how to produce its own values in order. for...in is built for something else entirely: it visits every enumerable key an object can see, including ones it only has because they were inherited from further up its prototype chain. That's precisely why it's the wrong choice for arrays — properties nobody put there on purpose can show up in the results, and on a plain object the order it visits non-numeric keys in isn't something to design around.
const feedback = { communication: 8, systemDesign: 7, coding: 9 };
for (const category in feedback) {
console.log(category, feedback[category]); // "communication" 8, then "systemDesign" 7, then "coding" 9
}
A gotcha most people never hit on purpose: sparse arrays
If you ever remove a candidate with delete instead of .splice(), here's what actually happens:
delete candidates[1]; // don't do this — it does NOT work like removing an item
candidates.length; // still 5 — delete doesn't shrink the array
candidates.forEach(c => console.log(c.name)); // logs 4 names, skipping index 1 entirely
candidates.map(c => c.name);
// [ "Priya Shah", <1 empty item>, "Amara Chen", "Sam Okafor", "Lena Fischer" ]
delete on an array index leaves a genuine hole — not undefined sitting at that index, but a slot with nothing there at all. .forEach(), .map(), and .filter() all skip holes silently rather than calling your callback with them, which is precisely why this bug hides so well: nothing throws, the array just quietly has one fewer thing happening at that position. .splice(1, 1) is almost always what you actually wanted — it removes the element and closes the gap, shrinking .length by one.