What are property descriptors?
By FrontendPro Editorial Team Updated 9/26/2026
Answer
Every property has hidden metadata alongside its value, called a descriptor. It controls whether the property can be changed, listed, or removed.
Object.getOwnPropertyDescriptor({ a: 1 }, "a");
// { value: 1, writable: true, enumerable: true, configurable: true }
The three flags
writable— can the value be reassigned.enumerable— does it show up infor...in,Object.keys, spread andJSON.stringify.configurable— can the property be deleted, and can these flags be changed later.
Properties you create with obj.a = 1 get all three as true. Properties created with defineProperty default to false for all three, which is the detail that surprises people:
const o = {};
Object.defineProperty(o, "id", { value: 7 });
o.id = 9; // silently ignored (throws in strict mode)
Object.keys(o); // [] — not enumerable
delete o.id; // false — not configurable
Accessor descriptors
A property is either a data property (value, writable) or an accessor one (get, set) — never both:
Object.defineProperty(o, "name", {
get() { return this._name; },
enumerable: true,
});
Where this actually matters
Hiding internal fields from JSON.stringify and Object.keys by making them non-enumerable. Defining true constants with writable: false. Understanding why class methods do not appear in Object.keys(instance) — prototype methods are non-enumerable by design.
configurable: false is a one-way door: once set, you cannot undo it, and you cannot delete the property afterwards.
Related helpers
Object.freeze sets writable and configurable to false on every own property — one level deep only. Object.seal prevents adding and deleting but still allows changing existing values. Object.defineProperties and Object.getOwnPropertyDescriptors work on several at once, and the latter is what you need to copy an object including its getters, which spread does not do.
