Object.keys()
The safe replacement for for...in, which walks the prototype chain. Its one surprise is ordering: integer-like keys come first, in numeric order, regardless of how you wrote them.
Demo
The second case is the one worth remembering. The keys were written in the order 2, b, 1, a — and they come back as 1, 2, b, a. Integer-like keys are always listed first in ascending NUMERIC order, and only then do string keys appear in insertion order. This is specified behaviour, not an implementation quirk, and it bites whenever an object is keyed by id and the order is assumed to be the order of insertion. Note also that keys are always strings, even when the source had numbers, and that nesting is not explored — only the top level.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| object | object | yes | Any object. Primitives are coerced — a string yields its indices, a number yields an empty array. null and undefined throw TypeError. |
Return value
string[] — The object OWN enumerable string keys. Never inherited ones, never symbols, never non-enumerable ones. Always strings, even for numeric keys.
Common patterns
for (const key of Object.keys(obj)) { }
const size = Object.keys(obj).length;
const isEmpty = Object.keys(obj).length === 0;
Examples
Pitfalls
Object.keys({b: 1, 2: 1, a: 1, 1: 1})
new Map([["b", 1], [2, 1], ["a", 1]]).keys()
Object.keys(maybeNull)
Object.keys(maybeNull ?? {})
const o = {}; Object.defineProperty(o, 'h', {value: 1}); Object.keys(o)
Object.getOwnPropertyNames(o)
Object.keys({1: "a"})[0] === 1
Number(Object.keys({1: "a"})[0]) === 1
When to use
- Iterating an object own properties
- Counting properties, or testing for emptiness
- Converting an object to an array to use array methods
- Anywhere for...in appears with a hasOwnProperty guard
- You want the values → Object.values
- You want both → Object.entries
- You need insertion order for numeric keys → a Map
- You need inherited or non-enumerable properties → getOwnPropertyNames, or for...in
Notes
FAQ
They are in order — numeric order. The specification requires integer-like keys to be listed first, ascending, before any string key. Only string keys follow insertion order. If insertion order matters for numeric keys, use a Map, whose ordering is guaranteed for every key type.
Object.keys({2: "b", 1: "a"}); // ['1', '2']