Object.getOwnPropertyNames()
ES5+Returns an array of every own string-keyed property name — enumerable or not — of the given object. It sees the hidden properties that Object.keys() skips, stopping only at Symbol keys and inherited members.
Syntax
Object.getOwnPropertyNames(obj)Parameters
obj Object The object whose enumerable and non-enumerable properties are to be returned
Return Value
An array of strings corresponding to the properties
Examples
const obj = { a: 1, b: 2 };
Object.defineProperty(obj, 'c', { value: 3, enumerable: false });
console.log(Object.keys(obj));
console.log(Object.getOwnPropertyNames(obj)); 📌 When to Use
Use Object.getOwnPropertyNames() when non-enumerable properties matter: auditing objects for hidden state, building devtools-style inspectors, verifying that a polyfill or library installed its methods non-enumerably, or discovering the method names on built-in prototypes — Object.getOwnPropertyNames(Array.prototype) lists dozens of methods where Object.keys() reports an empty array, which makes it the tool for generating API documentation or test-coverage checklists from live objects. Security-adjacent code also uses it to make sure serialization boundaries leak nothing unexpected: comparing its output against Object.keys() reveals exactly which properties are hidden from normal enumeration. Class instances deserve a note: methods declared in a class body live on the prototype, so inspecting an instance directly shows only data fields — walk Object.getPrototypeOf(instance) to enumerate the methods. For everyday data processing, stick with Object.keys(); reaching for getOwnPropertyNames signals to readers that you deliberately care about hidden properties. When Symbol keys must be included too, step up to Reflect.ownKeys(), which returns strings and Symbols in one call.
⚠️ Common Mistakes
Expecting identical output across environments for exotic objects - the specification fixes ordering for ordinary objects (integer-like keys ascending, then string keys in creation order), but Proxy handlers and host objects can report names the engine does not anticipate. Snapshot tests built on getOwnPropertyNames output from browser-provided objects like window or DOM nodes regularly break between browsers and versions; restrict such assertions to objects your own code constructs.
Inspecting a class instance and concluding it has no methods - methods declared in a class body live on the prototype, so getOwnPropertyNames(instance) shows only own data fields. Enumerate Object.getPrototypeOf(instance) to see the methods, including the non-enumerable constructor.
Feeding its output into logic that assumes enumerability - names returned here may be invisible to for...in, spread, and JSON.stringify(), so copying properties by this list and expecting them all to survive a later spread copy will silently drop the non-enumerable ones again.
Using Object.getOwnPropertyNames() when Object.keys() would suffice - the extra non-enumerable properties are rarely needed.
Forgetting that Symbol properties are not included - use Object.getOwnPropertySymbols() for those.
Expecting inherited properties - this method only returns own properties, not those from the prototype chain.
✅ Best Practices
Explore unfamiliar APIs from the console: Object.getOwnPropertyNames(SomeClass.prototype) dumps the real method surface of a library object even when everything is non-enumerable - often faster and more truthful than out-of-date documentation.
Compute the hidden-property delta when auditing: the names in getOwnPropertyNames() minus those in Object.keys() are exactly the non-enumerable properties, a concise report of what an object conceals from ordinary iteration and serialization.
For complete property enumeration including Symbols, combine with getOwnPropertySymbols: [...Object.getOwnPropertyNames(obj), ...Object.getOwnPropertySymbols(obj)]
Use Reflect.ownKeys(obj) as a modern alternative that returns both string and Symbol property names.
Create debugging tools that compare Object.keys() vs Object.getOwnPropertyNames() to find hidden properties.
⚡ Performance Notes
Object.getOwnPropertyNames() is O(n) over own properties and, like Object.keys(), materializes a fresh array per call — hoist it out of loops when the result is reused. Skipping the enumerability filter makes it marginally more work per property in some engines and marginally less in others; the difference never matters at application scale. What can matter is output size: on exotic or built-in objects the list is much larger than keys() suggests (a String object reports every character index plus length), so generic deep-inspection tools should expect big arrays and guard their recursion. Reflect.ownKeys() costs about the same while also returning Symbol keys. As always, per-frame or per-request reflection over large object graphs belongs behind caches; a property-name set only changes when properties are added or removed, which is rare for most objects after construction.
🌍 Real World Example
Complete Object Property Inspector
The inspectObject() utility contrasts every property-discovery API on one object: Object.keys() for the visible surface, Object.getOwnPropertyNames() to expose the non-enumerable hidden property, Object.getOwnPropertySymbols() for Symbol keys, and a summary that counts each category. The closing comparison with Reflect.ownKeys() shows the one call that returns everything at once. Inspectors like this are the fastest way to answer "what is really on this object?" when a library hides state in non-enumerable or Symbol-keyed properties that normal logging never displays.
function inspectObject(obj) {
const enumerable = Object.keys(obj);
const allProps = Object.getOwnPropertyNames(obj);
const symbols = Object.getOwnPropertySymbols(obj);
const nonEnumerable = allProps.filter(p => !enumerable.includes(p));
return {
enumerable: enumerable,
nonEnumerable: nonEnumerable,
symbols: symbols.map(s => s.toString()),
prototype: Object.getPrototypeOf(obj)?.constructor?.name || null,
summary: {
total: allProps.length + symbols.length,
visible: enumerable.length,
hidden: nonEnumerable.length,
symbolCount: symbols.length
}
};
}
// Create an object with various property types
const myObj = { visible1: 'a', visible2: 'b' };
// Add non-enumerable property
Object.defineProperty(myObj, 'hidden', {
value: 'secret',
enumerable: false
});
// Add Symbol property
const mySymbol = Symbol('mySymbol');
myObj[mySymbol] = 'symbol value';
// Inspect the object
const inspection = inspectObject(myObj);
console.log(inspection);
// {
// enumerable: ['visible1', 'visible2'],
// nonEnumerable: ['hidden'],
// symbols: ['Symbol(mySymbol)'],
// prototype: 'Object',
// summary: { total: 4, visible: 2, hidden: 1, symbolCount: 1 }
// }
// Compare different methods
console.log('Object.keys():', Object.keys(myObj));
// ['visible1', 'visible2']
console.log('Object.getOwnPropertyNames():', Object.getOwnPropertyNames(myObj));
// ['visible1', 'visible2', 'hidden']
console.log('Reflect.ownKeys():', Reflect.ownKeys(myObj));
// ['visible1', 'visible2', 'hidden', Symbol(mySymbol)]