Keys differ by ownership, enumerability and type. Object.keys returns own enumerable string keys; for-in can include inherited enumerable string keys.
Step-by-step walkthrough
Step 1: Classify the properties
An object can have own or inherited properties, enumerable or nonenumerable properties, and string or symbol keys. State which categories your operation needs. Serialization, configuration lookup and diagnostic inspection can each require a different set.
Step 2: Select the matching API
Object.keys exposes own enumerable string keys. Reflect.ownKeys exposes all own string and symbol keys. A for-in traversal includes enumerable inherited string keys, so protect ownership-sensitive work with Object.hasOwn rather than the in operator.
Step 3: Treat enumeration as a boundary
Do not automatically apply every discovered property to trusted configuration. Enumeration tells you what exists, not which fields are allowed or which values are safe. Validate the output contract independently, especially when input came from JSON or another external source.
Worked scenario
An inherited role is absent from Object.keys but may appear in for-in. Object.hasOwn tests ownership.
const inherited = {role: 'reader'};
const record = Object.create(inherited);
record.name = 'Ada';
Object.defineProperty(record, 'internal', {value: 42});
record[Symbol('trace')] = 'local';
console.log(Object.keys(record)); // ['name']
console.log(Reflect.ownKeys(record).length); // 3
console.log(Object.hasOwn(record, 'role')); // falseWalk through the example
The role is inherited. Internal is an own property whose enumerable flag defaults to false. The symbol is an own key but absent from Object.keys. Reflect.ownKeys sees name, internal and the symbol while still excluding the inherited role. These results follow property categories rather than visibility in a console.
Common mistake
The in operator checks prototypes too. Symbol keys are absent from Object.keys.
Verify the behavior
Test inherited enumerable values, nonenumerable own values and symbol keys. If a utility copies properties, also test getters because reading a property can execute code. Specify whether descriptors or just observed values should be copied.
Interview exercise
Enumerate all own keys.
Answer and reasoning
Reflect.ownKeys includes string and symbol keys, including non-enumerable ones; inspect descriptors when filtering.
Follow-up discussion
Why not use in for validation? It accepts inherited properties and can mistake inherited configuration for explicit input. Does Object.keys provide every own property? No: it omits symbols and nonenumerable string keys. Choose the narrower or broader enumeration deliberately.
Continue learning
Compare the scenario with the JavaScript interview questions and test your understanding with the JavaScript MCQs. For terminology and implementation details, consult the reference material.