Question

Count Object Properties Efficiently in JavaScript

javascriptperformancepropertiescountkey

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.

Take Quiz

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:

  1. inventory is created with three own enumerable properties: apples, oranges, and pears.

  2. Object.keys(inventory) examines the object and returns an array of its enumerable string keys:

    ["apples", "oranges", "pears"]
    
  3. That array is assigned to keys.

  4. keys.length is 3, because the array has three elements.

  5. 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
Take Quiz

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

ApproachCountsIncludes inherited properties?Best use
Object.keys(obj).lengthOwn enumerable string keysNoStandard count for ordinary objects
Object.getOwnPropertyNames(obj).lengthOwn string keys, enumerable and non-enumerableNoInclude hidden string properties
Reflect.ownKeys(obj).lengthOwn string and symbol keys, enumerable and non-enumerableNoInspect every own key
for...in with ownership checkOwn enumerable string keysNo, if checkedWhen processing each key manually
for...in aloneEnumerable own and inherited string keysYesRarely appropriate for a simple count
map.sizeEntries in a MapNot applicableDynamic 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.

Take Quiz

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...in includes 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.

Take Quiz

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.

Take Quiz

Keep learning

Related questions

View more