How to Use Object.defineProperty in JavaScript
JavaScript’s Object.defineProperty() method provides
granular control over how object properties behave by defining or
modifying property descriptors. While standard assignment simply creates
writable, enumerable, and configurable properties,
Object.defineProperty() allows developers to explicitly set
attributes such as writable, enumerable,
configurable, value, get, and
set. This guide explains how to use these descriptor
attributes to customize object properties effectively.
Syntax and Basics
The method accepts three arguments: the target object, the property name (a string or Symbol), and the descriptor object.
Object.defineProperty(obj, prop, descriptor);Property descriptors are divided into two main types: Data Descriptors and Accessor Descriptors. A descriptor must be one of these two types and cannot be both.
Data Descriptors
A data descriptor is a property that has a value, which may or may not be writable.
1. value
Defines the actual data stored in the property. It defaults to
undefined.
2. writable
Controls whether the property value can be changed using an
assignment operator (=). It defaults to false
when defined via Object.defineProperty().
const user = {};
Object.defineProperty(user, 'id', {
value: 101,
writable: false // Prevents modification
});
user.id = 202; // In strict mode, this throws a TypeError; otherwise, it fails silently
console.log(user.id); // Output: 101Shared Attributes
Both data and accessor descriptors share the following attributes:
1. enumerable
Determines whether the property shows up during enumeration, such as
in for...in loops or Object.keys(). It
defaults to false.
const car = {};
Object.defineProperty(car, 'engine', {
value: 'V8',
enumerable: false
});
console.log(Object.keys(car)); // Output: []
console.log(car.engine); // Output: 'V8'2. configurable
Determines whether the property can be deleted from the object and
whether its descriptor attributes can be modified later. It defaults to
false.
const account = {};
Object.defineProperty(account, 'iban', {
value: 'US123456789',
configurable: false
});
delete account.iban; // Fails to delete
// Attempting to re-define the descriptor will throw a TypeError:
// Object.defineProperty(account, 'iban', { enumerable: true });Accessor Descriptors
An accessor descriptor describes a property through a getter-setter pair instead of a fixed value.
1. get
A function that acts as a getter for the property. When the property
is accessed, the function is called with no arguments and its return
value becomes the property value. Defaults to
undefined.
2. set
A function that acts as a setter for the property. When the property
is assigned a value, the function is called with the assigned value as
its argument. Defaults to undefined.
const person = {
firstName: 'Jane',
lastName: 'Doe'
};
Object.defineProperty(person, 'fullName', {
get() {
return `${this.firstName} ${this.lastName}`;
},
set(name) {
const parts = name.split(' ');
this.firstName = parts[0];
this.lastName = parts[1];
},
enumerable: true,
configurable: true
});
console.log(person.fullName); // Output: Jane Doe
person.fullName = 'John Smith';
console.log(person.firstName); // Output: JohnSummary of Default Values
When creating new properties using regular assignment
(obj.prop = value), attributes default to
true. When using Object.defineProperty(),
omitted descriptor attributes default to false or
undefined.
| Attribute | Default via Assignment | Default via
Object.defineProperty |
|---|---|---|
value |
Specified value | undefined |
writable |
true |
false |
enumerable |
true |
false |
configurable |
true |
false |
get |
undefined |
undefined |
set |
undefined |
undefined |