Suggest an editImprove this articleRefine the answer for “Read-only properties”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**A read-only property is defined with `Object.defineProperty()` and `writable: false`, plus `configurable: false` when it must also survive deletion and redefinition.** To protect a whole object at once use `Object.freeze()`; for a computed value a getter without a setter is enough. `Object.seal()` is weaker: it forbids adding and deleting properties but still lets you change the values of existing ones. ```javascript Object.defineProperty(obj, 'key', { value: val, writable: false }); ``` **Key point:** one property, `defineProperty` with `writable: false`; the whole object, `Object.freeze()`. In strict mode a write throws `TypeError`, in sloppy mode it fails silently.Shown above the full answer for quick recall.Answer (EN)Image**In JavaScript a property can be made read-only, meaning it cannot be changed, deleted or redefined.** There are several ways to do it, from configuring a single property to freezing the entire object. ## Theory ### TL;DR - `Object.defineProperty(obj, key, { writable: false })` makes one specific property read-only. - Adding `configurable: false` also forbids deleting it or redefining its descriptor. - `Object.freeze(obj)` freezes the whole object: no changes, no additions, no deletions. - `Object.seal(obj)` is weaker: values can change, the object's shape cannot. - A getter without a setter gives you a computed read-only property. - In sloppy mode a failed write is ignored silently, in strict mode it throws `TypeError`. ### Quick example ```javascript const user = {}; Object.defineProperty(user, 'name', { value: 'Alice', writable: false, // forbids changing the value enumerable: true, // the property shows up when iterating configurable: false // cannot be deleted or redefined }); console.log(user.name); // "Alice" user.name = 'Bob'; // does not change the value console.log(user.name); // "Alice" delete user.name; // does not delete the property console.log(user.name); // "Alice" ``` ### Object.defineProperty This is the main way to define a property with exactly the attributes you want. `writable: false` makes it read-only, and `configurable: false` additionally prevents deletion and any further redefinition through `defineProperty`. You can inspect the attributes with the descriptor: ```javascript console.log(Object.getOwnPropertyDescriptor(user, 'name')); ``` It prints: ```javascript { value: 'Alice', writable: false, enumerable: true, configurable: false } ``` Note that when you create a property with `Object.defineProperty()` and omit the attributes, they all default to `false`. So the property ends up read-only whether you meant it or not. ### Object.freeze When every property has to become immutable at once, freeze the object: ```javascript const user = { name: 'Alice', age: 25 }; Object.freeze(user); user.name = 'Bob'; // does not change the value user.city = 'Kyiv'; // cannot add a new property delete user.age; // cannot delete an existing one console.log(user); // { name: 'Alice', age: 25 } ``` `Object.freeze()` does two things: - every existing property gets `writable: false` and `configurable: false`; - the object becomes non-extensible, so new properties cannot be added. Freezing is shallow: nested objects stay mutable, and `user.profile.city = 'Lviv'` still works. A deep freeze has to walk the object graph recursively. ### A getter without a setter For a computed value you do not need a descriptor at all: a property with `get` but no `set` is read-only by definition. ```javascript const user = { firstName: 'Alice', lastName: 'Smith', get fullName() { return `${this.firstName} ${this.lastName}`; } }; console.log(user.fullName); // "Alice Smith" user.fullName = 'Bob Jones'; // has no effect ``` ### Object.seal When a full freeze is too much and you only want to lock the shape of the object: ```javascript const user = { name: 'Alice' }; Object.seal(user); user.name = 'Bob'; // allowed delete user.name; // not allowed user.age = 30; // not allowed ``` Unlike `freeze()`, `seal()` lets you change the values of existing properties but forbids changing the set of keys. ### Comparison | Approach | What it does | Change a value | Add or delete | | --- | --- | --- | --- | | `Object.defineProperty(obj, key, { writable: false })` | Makes one property read-only | No | Yes | | `Object.freeze(obj)` | Freezes the whole object | No | No | | `Object.seal(obj)` | Forbids adding and deleting properties | Yes | No | | Getter without a setter | Computed read-only property | No | Yes | In one line: to make a property read-only use `Object.defineProperty(obj, 'key', { value: val, writable: false })`, or freeze the whole object with `Object.freeze(obj)`. ### Common mistakes - **Expecting an exception in sloppy mode.** Outside strict mode, assigning to a read-only property simply does nothing and raises no error, so the bug is easy to miss. In modules and classes, where strict mode is always on, the same code throws `TypeError`. - **Confusing `freeze` with `seal`.** `seal()` does not make properties read-only, it only locks the set of keys. - **Assuming `Object.freeze()` is deep.** Nested objects and arrays remain fully mutable after the parent is frozen. - **Forgetting `configurable: false`.** With `writable: false` but `configurable: true` the property can be redefined by another `Object.defineProperty()` call, which defeats the protection. - **Leaving attributes implicit.** In `Object.defineProperty()` an omitted `writable`, `enumerable` or `configurable` defaults to `false`, so the property may unexpectedly disappear from `Object.keys()` and from loops.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.