What is Object.defineProperty()?
Object.defineProperty() defines or modifies a property with fine-grained control over its behaviour, via a descriptor.
Descriptors — set value, writable, enumerable, and configurable.
Accessors — define get and set functions instead of a value.
Default — properties added this way are non-enumerable and read-only unless specified.
Powerful but verbose: great for libraries and computed properties; use plain assignment for everyday code.
const obj = {};
// Data property
Object.defineProperty(obj, 'name', {
value: 'John',
writable: false, // Cannot change value
enumerable: true, // Shows in Object.keys
configurable: false // Cannot delete or redefine
});
obj.name = 'Jane'; // Silently fails (or TypeError in strict)
console.log(obj.name); // 'John'
// Accessor property
let _age = 0;
Object.defineProperty(obj, 'age', {
get() { return _age; },
set(val) {
if (val < 0) throw new Error('Age must be positive');
_age = val;
},
enumerable: true,
configurable: true
});
obj.age = 25; // Calls setter
console.log(obj.age); // 25 (calls getter)
// Non-enumerable property (hidden from Object.keys)
Object.defineProperty(obj, '_internal', {
value: 'secret',
enumerable: false // Hidden from Object.keys, for...in
});
console.log(Object.keys(obj)); // ['name', 'age'] — _internal hiddenwritable: false makes the value read-only. configurable: false prevents deletion and redefinition. Accessor properties use get/set instead of value/writable. enumerable: false hides the property from Object.keys and for...in.
This is how frameworks implement reactive properties (Vue 2 uses defineProperty, Vue 3 uses Proxy).
Know four descriptor properties: value, writable, enumerable, configurable. Accessor descriptors use get/set. Non-enumerable properties are hidden from iteration.
Vue 2's reactivity system was built on defineProperty (Vue 3 switched to Proxy). Show the read-only and hidden property patterns.