JavaScript Enumerable Properties and Loops Explained
In JavaScript, object properties have hidden internal attributes that
dictate how they behave during execution. One of the most important
attributes is the enumerable flag, which determines whether
a property can be discovered during iteration. This article explains
what enumerable properties are, how to control their visibility using
native JavaScript methods, and how they directly affect loops and
serialization methods such as for...in,
Object.keys(), and JSON.stringify().
What Are Enumerable Properties?
An enumerable property is an object property with an internal
enumerable attribute set to true. When a
property is enumerable, it can be viewed and accessed by iteration
mechanisms that traverse an object’s keys.
By default, every property created via simple assignment or through an object literal is enumerable:
const user = {
name: "Alice",
age: 30
};
// Both 'name' and 'age' are enumerable by defaultYou can define non-enumerable properties using
Object.defineProperty() or
Object.defineProperties() by explicitly setting the
enumerable descriptor to false:
const user = {
name: "Alice"
};
Object.defineProperty(user, "id", {
value: 101,
enumerable: false,
writable: true,
configurable: true
});In this example, user.id exists and can be accessed
directly via user.id, but it will be hidden from standard
iteration methods.
How Enumerable Properties Affect Loops and Methods
The enumerable flag dictates which built-in JavaScript
operations will include a property.
1. The for...in Loop
The for...in loop traverses all enumerable properties of
an object, including inherited enumerable properties from its prototype
chain.
const car = {
make: "Toyota"
};
Object.defineProperty(car, "secretSerial", {
value: "XYZ123",
enumerable: false
});
for (let key in car) {
console.log(key); // Outputs only: "make"
}2.
Object.keys(), Object.values(), and
Object.entries()
These static methods return arrays of an object’s own enumerable property names, values, or key-value pairs, completely ignoring non-enumerable properties and prototype properties.
console.log(Object.keys(car)); // ["make"]
console.log(Object.values(car)); // ["Toyota"]
console.log(Object.entries(car)); // [["make", "Toyota"]]3. JSON.stringify()
JSON.stringify() serializes only an object’s own
enumerable properties into a JSON string. Any non-enumerable property is
omitted from the resulting string.
console.log(JSON.stringify(car)); // '{"make":"Toyota"}'4. Object Spread and
Object.assign()
Both the spread operator (...) and
Object.assign() copy only own enumerable properties from a
source object to a target object.
const copy = { ...car };
console.log(copy.secretSerial); // undefinedHow to Check and Access Non-Enumerable Properties
If you need to verify or retrieve non-enumerable properties, JavaScript provides specialized methods:
propertyIsEnumerable(): Checks whether a specific property is enumerable and belongs directly to the object.car.propertyIsEnumerable("make"); // true car.propertyIsEnumerable("secretSerial"); // falseObject.getOwnPropertyNames(): Returns an array of all own property names (both enumerable and non-enumerable), excluding symbols.Object.getOwnPropertyNames(car); // ["make", "secretSerial"]Reflect.ownKeys(): Returns all own property keys, including non-enumerable keys and Symbol keys.Reflect.ownKeys(car); // ["make", "secretSerial"]
Summary of Loop Behavior
| Method / Operator | Includes Own Enumerable | Includes Inherited Enumerable | Includes Non-Enumerable |
|---|---|---|---|
for...in |
Yes | Yes | No |
Object.keys() |
Yes | No | No |
Object.assign() / Spread
(...) |
Yes | No | No |
JSON.stringify() |
Yes | No | No |
Object.getOwnPropertyNames() |
Yes | No | Yes |
Reflect.ownKeys() |
Yes | No | Yes |