Object.keys()
Returns an array of an object's own enumerable string-keyed property names.
Object.keys(obj)- Added in JavaScript ES5 (2009)
Parameters
| Parameter | Type | Description |
|---|---|---|
$obj | Object | An object. Values that are not objects are coerced to objects first, except null and undefined. |
Return value
Array<string>An array of strings representing the given object's own enumerable string-keyed property keys.
Errors
Throws a TypeError if obj is null or undefined, since neither can be coerced to an object.
Changelog
- PHP ES2015Non-object arguments are coerced instead of throwing. Object.keys("foo") now returns ["0","1","2"] and Object.keys(100) returns []; in ES5 both threw a TypeError.
Object.keys() gives you the names an object owns, as an array of strings. Two filters apply: the property must be an own property, so nothing inherited through the prototype chain appears, and it must be enumerable, so anything defined via Object.defineProperty() without enumerable: true is skipped. Symbol keys never show up either — they are not string keys.
When to reach for it
Reach for it whenever you want to treat an object as a collection: counting fields with .length, testing emptiness, mapping over field names, or comparing the shape of two objects. If you need the values as well, Object.entries() saves you a lookup per key.
What trips people up
The order is not purely insertion order. Integer-like keys come first in ascending numeric order, then string keys in insertion order, then symbols (which this method omits). So Object.keys({ 100: 'a', 2: 'b', x: 'c' }) is ['2', '100', 'x'], which surprises people building ordered maps from objects — use a Map if order matters.
The returned keys are always strings, even for arrays: Object.keys([10, 20]) is ['0', '1'], not numbers. And the array is a fresh snapshot, not a live view — mutating the object afterwards does not update it.
Example
When to use it
- Check whether a config object is empty with Object.keys(cfg).length === 0
- Render a table header row from the field names of a record
- Compare two API responses to find which fields were added or dropped
- Iterate an object's own fields without picking up inherited prototype properties
Frequently asked questions
Does Object.keys() include inherited properties?
No — it returns own properties only. Inherited properties from the prototype chain are excluded, which is the main difference from a for...in loop.
Why is Object.keys() missing a property I definitely set?
The property is almost certainly non-enumerable or a symbol. Properties added with Object.defineProperty() default to enumerable: false, and symbol keys are never returned; use Object.getOwnPropertyNames() or Object.getOwnPropertySymbols() to see them.
Is the order of Object.keys() guaranteed?
Yes, but it is not insertion order: integer-like keys come first in ascending numeric order, then the remaining string keys in insertion order.
More examples
Emptiness check
The third case prints true: the object has an inherited property but owns nothing, and Object.keys() only counts own properties.
const isEmpty = (o) => Object.keys(o).length === 0;
console.log(isEmpty({}));
console.log(isEmpty({ a: 1 }));
console.log(isEmpty(Object.create({ inherited: 1 })));Diffing two shapes
Shows that key lists are ordinary arrays, so array methods do the shape comparison for you.
const v1 = { id: 1, name: "a", legacy: true };
const v2 = { id: 1, name: "a", email: "[email protected]" };
const a = Object.keys(v1);
const b = Object.keys(v2);
console.log("removed:", a.filter((k) => !b.includes(k)));
console.log("added:", b.filter((k) => !a.includes(k)));Coercion of primitives
Since ES2015 primitives are coerced rather than rejected, so only null and undefined throw a TypeError.
console.log(Object.keys("hey")); // string indices are own enumerable props
console.log(Object.keys(42)); // numbers have no own enumerable props
console.log(Object.keys([7, 8])); // array indices, as strings
try {
Object.keys(null);
} catch (err) {
console.log(err.constructor.name);
}
Discussion