Question
What is the most efficient way to count the keys (properties) of a JavaScript object?
Can this be done without iterating through the object's properties, rather than using a loop such as:
let count = 0;
for (const key in myobj) {
if (Object.prototype.hasOwnProperty.call(myobj, key)) {
count++;
}
}
Older Firefox versions provided a non-standard __count__ property, but it was removed. What is the standard JavaScript approach?
Short Answer
You will learn how to count an object's own enumerable properties with Object.keys(obj).length, why JavaScript must inspect properties to produce the count, and when alternatives such as Map.size are a better fit.
Concept
JavaScript objects do not have a standard built-in property count such as object.length or object.size.
For ordinary objects, the standard approach is:
const count = Object.keys(myobj).length;
Object.keys(myobj) creates an array containing the object's own enumerable string-keyed property names. The array's length is therefore the count.
const user = {
name: "Ava",
role: "admin",
active: true
};
console.log(Object.keys(user).length); // 3
This is usually clearer and less error-prone than writing a for...in loop yourself.
Why counting still requires work
Conceptually, JavaScript needs to determine which properties qualify for the count. There is no portable standard API that promises an instant count for all ordinary object properties. Even if a JavaScript engine internally tracks metadata, your code should use the standard API rather than relying on engine-specific implementation details.
Also note that “property count” can mean different things:
- Own properties only, or inherited properties too?
- Enumerable properties only, or non-enumerable ones too?
- String keys only, or symbol keys too?
Object.keys() answers the common case: own, enumerable, string-keyed properties.
Mental Model
Think of an object as a cabinet of labeled drawers.
- Own properties are drawers physically inside this cabinet.
- Inherited properties are drawers available through a cabinet it was built from (its prototype).
- Enumerable properties are drawers included in the normal inventory list.
- Non-enumerable properties exist, but are intentionally left off that normal list.
Object.keys(cabinet) produces the normal inventory list for this cabinet. Then .length counts the labels on that list.
If you constantly need to know how many items are stored, an object is like a cabinet without a visible item counter. A Map is more like a collection with a built-in counter: map.size.
Syntax and Examples
The usual syntax is:
const count = Object.keys(object).length;
Example:
const scores = {
maya: 98,
liam: 87,
noah: 91
};
const numberOfScores = Object.keys(scores).length;
console.log(numberOfScores); // 3
Object.keys(scores) returns:
["maya", "liam", "noah"]
The array contains three names, so its .length is 3.
Empty object
const settings = {};
console.log(Object.keys(settings).length); // 0
Symbols are not included by Object.keys
const id = Symbol("id");
const record = {
name: "Maya",
[id]: 42
};
console.log(Object.keys(record)); // ["name"]
console.log(Object.keys(record).length); // 1
To count both enumerable string keys and enumerable symbol keys:
const count = Object.keys(record).length + Object.getOwnPropertySymbols(record).length;
console.log(count); // 2
Use this only when symbol properties are relevant to your program.
Step by Step Execution
Consider this code:
const inventory = {
apples: 12,
oranges: 8,
pears: 5
};
const keys = Object.keys(inventory);
const count = keys.length;
console.log(count);
Step by step:
-
inventoryis created with three own enumerable properties:apples,oranges, andpears. -
Object.keys(inventory)examines the object and returns an array of its enumerable string keys:["apples", "oranges", "pears"] -
That array is assigned to
keys. -
keys.lengthis3, because the array has three elements. -
console.log(count)prints:3
A compact version performs the same operations:
console.log(Object.keys(inventory).length); // 3
Real World Use Cases
Counting object properties is useful when an object acts as a dictionary or lookup table.
Check whether a form has validation errors
const errors = {
email: "Enter a valid email address",
password: "Password is too short"
};
if (Object.keys(errors).length > 0) {
console.log("The form has errors.");
}
Count cached records
const cache = {
"user:101": { name: "Ava" },
"user:102": { name: "Omar" }
};
console.log(`Cached users: ${Object.keys(cache).length}`);
Determine whether an API result contains fields
const responseData = {};
if (Object.keys(responseData).length === 0) {
console.log("The API returned no fields.");
}
Build a dashboard summary
const ticketsById = {
T100: { status: "open" },
T101: { status: "closed" },
T102: { status: "open" }
};
const totalTickets = Object.keys(ticketsById).length;
console.log(totalTickets); // 3
Real Codebase Usage
In real applications, Object.keys(obj).length is common for occasional checks, especially with plain JSON-like data.
Prefer an emptiness check when that is all you need
If you only need to know whether an object has at least one own enumerable string property, this is readable:
function hasValues(value) {
return Object.keys(value).length > 0;
}
Use it after validating that value is an object when input may be null, an array, or another type.
Use guard clauses for validation
function saveProfile(updates) {
if (Object.keys(updates).length === 0) {
throw new Error("Provide at least one profile update.");
}
// Save the updates...
}
Track the count separately for frequently changing collections
If you add and remove records often and need the count repeatedly, do not repeatedly call Object.keys(records).length. Use Map, whose size is designed for this:
const sessions = new Map();
sessions.set("session-a", { userId: 1 });
sessions.set("session-b", { userId: 2 });
console.log(sessions.size); // 2
Use Object.create(null) for pure dictionaries when appropriate
Objects created with Object.create(null) have no prototype, which can be useful for simple key-value dictionaries:
const counts = Object.create(null);
counts.apple = 2;
console.log(Object.keys(counts).length); // 1
This does not make counting free, but it avoids inherited object methods and prototype-related key collisions.
Common Mistakes
Expecting object.length to work
Plain objects do not automatically have a length property.
const user = { name: "Ava", role: "admin" };
console.log(user.length); // undefined
Use:
console.log(Object.keys(user).length); // 2
Using for...in without considering inherited properties
for...in visits enumerable properties from the object and its prototype chain.
const parent = { inherited: true };
const child = Object.create(parent);
child.own = true;
for (const key in child) {
console.log(key);
}
// Logs "own" and "inherited"
To count only own enumerable string properties, use Object.keys(child).length.
If a for...in loop is necessary, safely test ownership:
for (const key in child) {
if (Object.prototype.hasOwnProperty.call(child, key)) {
console.log(key);
}
}
Calling obj.hasOwnProperty() directly
An object can override hasOwnProperty, or it may have no prototype.
const data = {
hasOwnProperty: "not a function",
name: "Ava"
};
// data.hasOwnProperty("name"); // TypeError
Use Object.prototype.hasOwnProperty.call(data, "name"), or use Object.hasOwn(data, "name") in modern JavaScript.
Forgetting that Object.keys() excludes symbols and non-enumerable properties
const item = {};
Object.defineProperty(item, "hidden", { value: 1 });
console.log(Object.keys(item).length); // 0
The hidden property is non-enumerable by default. If you truly need every own property name, use Reflect.ownKeys(item).
Recounting inside a loop
Avoid recalculating a count when it does not change:
// Less efficient and harder to read
for (let i = 0; i < Object.keys(data).length; i++) {
// ...
}
Store the keys once:
const keys = Object.keys(data);
for (let i = 0; i < keys.length; i++) {
// ...
}
Comparisons
| Approach | Counts | Includes inherited properties? | Best use |
|---|---|---|---|
Object.keys(obj).length | Own enumerable string keys | No | Standard count for ordinary objects |
Object.getOwnPropertyNames(obj).length | Own string keys, enumerable and non-enumerable | No | Include hidden string properties |
Reflect.ownKeys(obj).length | Own string and symbol keys, enumerable and non-enumerable | No | Inspect every own key |
for...in with ownership check | Own enumerable string keys | No, if checked | When processing each key manually |
for...in alone | Enumerable own and inherited string keys | Yes | Rarely appropriate for a simple count |
map.size | Entries in a Map | Not applicable | Dynamic key-value collection with frequent size checks |
Object versus Map
const objectStore = { a: 1, b: 2 };
console.log(Object.keys(objectStore).length); // 2
const mapStore = new Map([["a", 1], ["b", 2]]);
console.log(mapStore.size); // 2
Use a plain object for structured records and JSON-like data. Consider Map when a collection is updated often, keys may not be strings, or .size is needed frequently.
Cheat Sheet
// Standard: own enumerable string-keyed properties
const count = Object.keys(obj).length;
// Is a plain object empty in the Object.keys sense?
const isEmpty = Object.keys(obj).length === 0;
// Own string keys, including non-enumerable keys
const allStringKeyCount = Object.getOwnPropertyNames(obj).length;
// All own keys: strings, symbols, enumerable, and non-enumerable
const allKeyCount = Reflect.ownKeys(obj).length;
// Count symbols separately when needed
const enumerableStringAndSymbolCount =
Object.keys(obj).length + Object.getOwnPropertySymbols(obj).length;
// Safe ownership test in a for...in loop
Object.prototype.hasOwnProperty.call(obj, key);
// Modern ownership test
Object.hasOwn(obj, key);
// A Map exposes a collection size directly
const countFromMap = map.size;
Key rules:
Object.keys()does not include inherited properties.Object.keys()does not include symbol keys.Object.keys()does not include non-enumerable properties.for...inincludes inherited enumerable properties unless you filter them.- There is no standard
__count__property for ordinary JavaScript objects.
FAQ
What is the simplest way to count object properties in JavaScript?
Use Object.keys(obj).length. It counts the object's own enumerable string-keyed properties.
Is there an object .size property in JavaScript?
Plain objects do not have .size. Map and Set have a .size property.
Does Object.keys() count inherited properties?
No. It returns only keys that belong directly to the object.
Does for...in count inherited properties?
Yes. A for...in loop visits enumerable properties from the prototype chain as well. Filter with an ownership check if you use it.
Does Object.keys() count symbol properties?
No. Use Object.getOwnPropertySymbols(obj) for symbols, or Reflect.ownKeys(obj) for all own keys.
Can I count object properties without iteration?
There is no standard, general-purpose property-count field on ordinary objects. Object.keys() is the standard API, and it must determine the matching keys.
Which is faster: Object.keys() or a for...in loop?
For most code, choose Object.keys(obj).length because it is clear and standard. Exact performance depends on the engine and object shape; benchmark only when profiling identifies this as a real bottleneck.
When should I use a Map instead of an object?
Use Map for a dynamic key-value collection when you frequently add, remove, and count entries, especially if keys are not limited to strings or symbols.
Mini Project
Description
Build a small validation helper for a profile update endpoint. The helper receives an object of field errors and reports whether saving can continue. This demonstrates counting an object's keys without accidentally including inherited properties.
Goal
Create a function that returns a readable status message based on the number of validation errors in an object.
Requirements
Use Object.keys() to count validation error fields.
Return "No validation errors" when the object has no error fields.
Return a singular message for exactly one error.
Return a plural message for two or more errors.
Test the function with empty, one-error, and multiple-error objects.
Keep learning
Related questions
Abort Ajax Requests with jQuery jqXHR.abort()
Learn how to cancel an in-progress jQuery Ajax request with jqXHR.abort(), handle abort status safely, and avoid stale UI updates.
Access the Correct this Inside a JavaScript Callback
Learn why JavaScript this changes in callbacks and how to preserve an object context using bind, arrow functions, and event handler patterns.
Add Key-Value Pairs to JavaScript Objects
Learn how to add key-value pairs to JavaScript objects with dot and bracket notation, dynamic keys, examples, and common mistakes.