JavaScript Development Space

Object.freeze() and Object.seal() in JavaScript

Previously, we wrote about How to Create Immutable Objects in JavaScript. In this howto, we'll explore the difference between Object.freeze() and Object.seal().

Object.freeze() and Object.seal() in JavaScript

Both Object.freeze() and Object.seal() are methods used to control how objects behave when modified, but they have distinct differences. Here's how each works:

Object.freeze()

The Object.freeze() method "freezes" an object, preventing any changes to its properties. This means:

  • No new properties can be added to the object.
  • Existing properties cannot be removed.
  • Modifications to existing properties (like changing values) are not allowed.
  • Reconfiguring property descriptors (like changing from writable to non-writable) is not allowed.
  • The object becomes immutable, but note that for nested objects, only the outer object is frozen, not the deeper properties.

Example:

js
1 const person = { name: 'Alice', age: 30 };
2
3 // Freeze the object
4 Object.freeze(person);
5
6 // Trying to modify properties
7 person.age = 25; // This will not work
8 person.city = 'New York'; // Adding new property will also fail
9
10 console.log(person); // Output: { name: "Alice", age: 30 }

Key Points:

  • It makes the object completely immutable.
  • No changes to the object's structure or values are allowed.

As you can see, all attempts to modify the object failed. On a low level, Object.freeze() adds a non-configurable flag to all the object’s properties, preventing them from being altered.

However, if there are nested objects, Object.freeze() does not automatically freeze them. This means that the properties of nested objects can still be modified:

js
1 const person = {
2 name: 'Alice',
3 age: 30,
4 address: {
5 city: 'New York',
6 },
7 };
8
9 // Freeze the object
10 Object.freeze(person);
11
12 // Trying to modify properties
13 person.address.city = 'Los Angeles'; // This will work

To freeze nested objects, you’ll need to do it manually or write a recursive function. DeepFreeze a nested Object/Array

Object.seal()

The Object.seal() method "seals" an object, restricting certain modifications but still allowing others:

  • No new properties can be added.
  • Existing properties cannot be removed.
  • Modifying existing properties (like changing their values) is allowed.
  • Property descriptors (like configurable) are set to false, meaning properties can't be redefined or removed.
  • The object’s structure is sealed, but values can still be updated.

Example:

js
1 const car = { make: 'Chevrolet', model: 'Spark' };
2
3 // Seal the object
4 Object.seal(car);
5
6 // Trying to add a new property
7 car.year = 2022; // This will not work
8
9 // Modifying an existing property
10 car.model = 'Camaro'; // This will work
11
12 console.log(car); // Output: { make: "Toyota", model: "Camaro" }

Key Points:

  • Sealed objects can have their existing properties modified.
  • New properties cannot be added, and existing properties cannot be deleted.

Usage Examples

Protecting Configuration Objects

Configuration objects define the behavior of your application. They need to remain stable and unchangeable to avoid accidental errors:

js
1 const config = {
2 apiUrl: 'https://api-domain.com',
3 timeout: 4000,
4 retries: 2,
5 };
6
7 Object.freeze(config);
8
9 // Function to Retrieve Configuration
10 function getConfig() {
11 return config;
12 }
13
14 // Usage Example
15 console.log(getConfig().apiUrl); // "https://api-domain.com"
16
17 // Attempt to Modify Configuration
18 config.apiUrl = 'https://new-api-domain.com'; // This will not work
19 console.log(getConfig().apiUrl); // Still "https://api-domain.com"

By using Object.freeze(), we ensure that any attempts to modify config will be ignored.

Usage in Redux Library

In Redux, immutability of the state is key to predictability and easier debugging. By using Object.freeze(), you can protect the state from unwanted mutations.

Example:

js
1 const initialState = {
2 user: null,
3 loggedIn: false,
4 };
5
6 function reducer(state = initialState, action) {
7 switch (action.type) {
8 case 'LOGIN':
9 return Object.freeze({
10 ...state,
11 user: action.payload,
12 loggedIn: true,
13 });
14 case 'LOGOUT':
15 return Object.freeze(initialState);
16 default:
17 return state;
18 }
19 }

Here, we use Object.freeze() to ensure that each time the state is updated, it remains unchanged.

Example with React

In React, managing component state is often necessary. Protecting state using Object.freeze() can help prevent errors caused by data mutations.

Example:

js
1 import React, { useState } from 'react';
2
3 const App = () => {
4 const [config, setConfig] = useState(
5 Object.freeze({
6 theme: 'light',
7 notificationsEnabled: true,
8 }),
9 );
10
11 const toggleTheme = () => {
12 // Создаем новый объект вместо изменения существующего
13 setConfig((prevConfig) =>
14 Object.freeze({
15 ...prevConfig,
16 theme: prevConfig.theme === 'light' ? 'dark' : 'light',
17 }),
18 );
19 };
20
21 return (
22 <div style={{ background: config.theme === 'light' ? '#fff' : '#333' }}>
23 <h1>Текущая тема: {config.theme}</h1>
24 <button onClick={toggleTheme}>Сменить тему</button>
25 </div>
26 );
27 };
28
29 export default App;

In this example, we use Object.freeze() to protect the configuration state.

Protecting Constants and Global Variables

When working with constants, you may need to ensure that these values are not accidentally modified. With Object.freeze(), you can make constants truly immutable.

Example:

js
1 const constants = Object.freeze({
2 MAX_CONNECTIONS: 150,
3 DEFAULT_TIMEOUT: 4000,
4 APP_NAME: 'MyApp',
5 });
6
7 // Attempting to modify a constant
8 constants.MAX_CONNECTIONS = 100; // Will not work
9
10 console.log(constants.MAX_CONNECTIONS); // 150

In this example, even if someone tries to change MAX_CONNECTIONS, the modification will not occur, and your application will remain stable.

Summary of Differences

  • Object.freeze() makes an object completely immutable, preventing any changes, including modifications to values.
  • Object.seal() allows modifying existing properties but prevents adding or removing properties.

These methods are useful for locking down objects to prevent accidental or unwanted changes.

JavaScript Development Space

© 2024 JavaScript Development Space - Master JS and NodeJS. All rights reserved.