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
prototypeis skipped. - Enumerable properties only, keys defined with
enumerable: falsenever 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()andObject.entries().
Quick example
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
Object.keys(obj)objis 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:
console.log(Object.keys({})); // []
console.log(Object.keys({}).length); // 0This 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
-
Own properties only, not the ones inherited through
prototype:javascriptconst person = { species: 'human' }; const user = Object.create(person); user.name = 'Maria'; console.log(Object.keys(user)); // ['name']The
specieskey lives on the prototype, so it is not in the array even though'species' in userreturnstrue. -
Enumerable properties only. A property created with
enumerable: falsewill not show up:javascriptconst config = {}; Object.defineProperty(config, 'secret', { value: 42, enumerable: false }); config.visible = 1; console.log(Object.keys(config)); // ['visible'] -
Symbol keys are ignored. There is a separate method for them:
javascriptconst 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:
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.
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:
const user = { name: 'Maria', age: 25, city: 'Kyiv' };
Object.values(user); // ['Maria', 25, 'Kyiv']Get an array of key-value pairs:
Object.entries(user);
// [['name', 'Maria'], ['age', 25], ['city', 'Kyiv']]All three methods share the same selection rules: own, enumerable, non-symbol properties.
| Method | Returns | Sees the prototype | Data type |
|---|---|---|---|
Object.keys(obj) | the list of keys | No | Array of strings |
Object.values(obj) | the list of values | No | Array |
Object.entries(obj) | array of [key, value] pairs | No | Array of arrays |
Iterating the keys in practice
const user = { name: 'Maria', age: 25, city: 'Kyiv' };
Object.keys(user).forEach(key => {
console.log(`${key}: ${user[key]}`);
});Output:
name: Maria
age: 25
city: KyivBecause the result is a plain array, every array method is available:
// 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 afor...inloop or theinoperator. - Confusing it with
for...in. Afor...inloop walks both own and inherited enumerable properties, which is why it usually needs anObject.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
Mapor 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
nullorundefined.Object.keys(null)throws aTypeError. Since ES2015 primitives no longer throw, but they give an almost always empty array:Object.keys(42)returns[].
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.