Skip to main content

The Object.keys() method

Object.keys() is a built-in JavaScript method that returns an array of all own (non-inherited) property names of an object, as strings. It is the simplest way to turn an object into an array you can then iterate, filter or count.

Theory

TL;DR

  • Returns an array of strings with property names.
  • Own properties only, anything inherited through prototype is skipped.
  • Enumerable properties only, keys defined with enumerable: false never appear.
  • Symbol keys are skipped too, Object.getOwnPropertySymbols() exists for those.
  • Order: integer-like keys first in ascending order, then the rest in insertion order.
  • Works together with Object.values() and Object.entries().

Quick example

javascript
const user = { name: 'Maria', age: 25, city: 'Kyiv' }; console.log(Object.keys(user)); // ['name', 'age', 'city']

All own enumerable keys of the object come back in a single array.

Syntax

javascript
Object.keys(obj)
  • obj is the object you want the list of keys from.
  • It returns an array of strings.

For an empty object the result is empty as well:

javascript
console.log(Object.keys({})); // [] console.log(Object.keys({}).length); // 0

This is exactly what the most common "is the object empty" check is built on: Object.keys(obj).length === 0.

Which properties end up in the result

  1. Own properties only, not the ones inherited through prototype:

    javascript
    const person = { species: 'human' }; const user = Object.create(person); user.name = 'Maria'; console.log(Object.keys(user)); // ['name']

    The species key lives on the prototype, so it is not in the array even though 'species' in user returns true.

  2. Enumerable properties only. A property created with enumerable: false will not show up:

    javascript
    const config = {}; Object.defineProperty(config, 'secret', { value: 42, enumerable: false }); config.visible = 1; console.log(Object.keys(config)); // ['visible']
  3. Symbol keys are ignored. There is a separate method for them:

    javascript
    const id = Symbol('id'); const user = { name: 'Maria', [id]: 1 }; console.log(Object.keys(user)); // ['name'] console.log(Object.getOwnPropertySymbols(user)); // [Symbol(id)]

The order of the keys

For ordinary string keys the order matches the order in which they were added to the object:

javascript
const o = {}; o.b = 1; o.a = 2; console.log(Object.keys(o)); // ['b', 'a']

The exception is integer-like keys: they always come first and are sorted in ascending order.

javascript
const mixed = { b: 1, 2: 'two', a: 3, 1: 'one' }; console.log(Object.keys(mixed)); // ['1', '2', 'b', 'a']

Note that numeric keys come back as strings, because keys of a plain object are always strings.

The neighbouring methods: Object.values and Object.entries

Get the list of values:

javascript
const user = { name: 'Maria', age: 25, city: 'Kyiv' }; Object.values(user); // ['Maria', 25, 'Kyiv']

Get an array of key-value pairs:

javascript
Object.entries(user); // [['name', 'Maria'], ['age', 25], ['city', 'Kyiv']]

All three methods share the same selection rules: own, enumerable, non-symbol properties.

MethodReturnsSees the prototypeData type
Object.keys(obj)the list of keysNoArray of strings
Object.values(obj)the list of valuesNoArray
Object.entries(obj)array of [key, value] pairsNoArray of arrays

Iterating the keys in practice

javascript
const user = { name: 'Maria', age: 25, city: 'Kyiv' }; Object.keys(user).forEach(key => { console.log(`${key}: ${user[key]}`); });

Output:

javascript
name: Maria age: 25 city: Kyiv

Because the result is a plain array, every array method is available:

javascript
// how many properties there are in total Object.keys(user).length; // 3 // pick only the string values Object.keys(user).filter(key => typeof user[key] === 'string'); // ['name', 'city']

Common mistakes

  • Expecting inherited properties. Object.keys() shows nothing from the prototype. If you need inherited keys too, use a for...in loop or the in operator.
  • Confusing it with for...in. A for...in loop walks both own and inherited enumerable properties, which is why it usually needs an Object.hasOwn(obj, key) guard inside. Object.keys() has that filter built in.
  • Looking for symbol or non-enumerable keys in the result. They are never there; Object.getOwnPropertyNames() gives the full list of string keys.
  • Relying on strict insertion order. Integer-like keys always float to the top and get sorted, so use a Map or an array when the order must be guaranteed.
  • Forgetting that keys are strings. Object.keys({ 1: 'one' }) returns ['1'], not [1], so a comparison against a number will fail.
  • Passing null or undefined. Object.keys(null) throws a TypeError. Since ES2015 primitives no longer throw, but they give an almost always empty array: Object.keys(42) returns [].

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.