for...in Loop: Key Enumeration & Prototype CaveatsThe for...in statement iterates over all enumerable string properties of an object, including properties inherited from its prototype chain.
for...in Property Search Flowflowchart TD
Start["for (const key in obj)"] --> CheckKey["Inspect next property key"]
CheckKey --> IsEnum{"Is property enumerable?"}
IsEnum -- "Yes" --> IsOwn{"Is own property or inherited prototype?"}
IsOwn -- "Own Property" --> YieldKey["Yield Key"]
IsOwn -- "Inherited" --> CheckHasOwn{"Filtered with Object.hasOwn()?"}
CheckHasOwn -- "Yes" --> YieldKey
CheckHasOwn -- "No" --> YieldProtoKey["Yield Inherited Key (Potential Bug!)"]
for...in vs for...of Comparison| Feature | for...in |
for...of |
|---|---|---|
| Iterates Over | Property Keys / Names (Strings) | Iterable Values (Elements) |
| Primary Use Case | Plain Objects ({ a: 1, b: 2 }) |
Arrays, Strings, Sets, Maps |
| Includes Prototype Keys? | Yes (Inherited enumerable properties) | No |
| Array Order Guaranteed? | No (Array index order is not guaranteed) | Yes (Sequential array order) |
// Demonstrating for...in on objects and prototype filtering
const parentConfig = { theme: "dark" };
const userSettings = Object.create(parentConfig); // Inherits theme from parentConfig
userSettings.fontSize = "16px";
userSettings.language = "en";
console.log("--- Unfiltered for...in Loop (Includes Prototype) ---");
for (const key in userSettings) {
console.log(`Key: ${key}, Value: ${userSettings[key]}`);
}
// Outputs: fontSize, language, AND inherited 'theme'!
console.log("
--- Safe for...in Loop (Filtered with Object.hasOwn) ---");
for (const key in userSettings) {
if (Object.hasOwn(userSettings, key)) {
console.log(`Own Key: ${key}, Value: ${userSettings[key]}`);
}
}
// Outputs ONLY own properties: fontSize, language
for...in for Arrays: for...in iterates over string keys (including custom array properties) and does not guarantee index order. Use for...of or .forEach() for arrays.Object.hasOwn(): Always check if (Object.hasOwn(obj, key)) when iterating plain objects with for...in.Object.keys() or Object.entries(): Modern JavaScript prefers for (const [key, val] of Object.entries(obj)) over for...in.Explain why for (const index in [10, 20, 30]) logs "0", "1", "2" as strings rather than numbers.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With
Experiment with the code from this lesson in our interactive playground.