JavaScript > Objects and Arrays > Advanced Object Concepts > Object.freeze()

Freezing Objects in JavaScript with Object.freeze()

Learn how to use Object.freeze() in JavaScript to create immutable objects, preventing modifications to their properties. This guide covers basic usage, deep freezing, use cases, best practices, and potential drawbacks.

Basic Object.freeze() Example

Object.freeze() prevents the addition of new properties, deletion of existing properties, and modification of the values of existing properties. Attempting to modify a frozen object will either fail silently (in non-strict mode) or throw a TypeError (in strict mode). It's a shallow freeze, meaning that if the object contains other objects as properties, those nested objects are not automatically frozen.

// Creating a simple object
const myObject = {
  name: 'Example',
  value: 10
};

// Freezing the object
Object.freeze(myObject);

// Attempting to modify the object
myObject.value = 20; // This will fail in strict mode, otherwise be ignored
myObject.newProperty = 'Test'; // This will fail in strict mode, otherwise be ignored

console.log(myObject); // Output: { name: 'Example', value: 10 }

Concepts behind the snippet

The core concept is immutability. Immutable objects are a cornerstone of functional programming and can improve code predictability and prevent unintended side effects. Freezing an object makes it read-only, ensuring that its state remains consistent throughout the application lifecycle after it has been frozen. It's important to note that Object.freeze only provides shallow immutability. To achieve deep immutability, you would need to recursively freeze all nested objects.

Deep Freezing Implementation

This code demonstrates a recursive function deepFreeze that iterates through the object's properties. If a property is an object (and not null), the function recursively calls itself to freeze that nested object. This ensures that all levels of the object are frozen, achieving deep immutability. A check for hasOwnProperty is used to avoid iterating over properties inherited from the prototype chain. Also adding a check to not freeze null values.

function deepFreeze(obj) {
  // Freeze the object itself
  Object.freeze(obj);

  // Iterate through properties and recursively freeze if they are objects
  for (let key in obj) {
    if (obj.hasOwnProperty(key) && (typeof obj[key] === 'object' || typeof obj[key] === 'function') && obj[key] !== null) {
      deepFreeze(obj[key]);
    }
  }

  return obj;
}

// Example usage:
const deepObject = {
  level1: {
    level2: {
      value: 100
    }
  }
};

deepFreeze(deepObject);

// Attempting to modify a deeply frozen object
deepObject.level1.level2.value = 200; // This will fail in strict mode or be ignored.

Real-Life Use Case Section

Consider a configuration object used throughout your application. Freezing this object ensures that the configuration settings remain constant and are not accidentally modified during runtime. Another common use case is in Redux or other state management libraries, where the state should be treated as immutable to ensure predictable state transitions.

Best Practices

  • Apply Early: Freeze objects as early as possible in their lifecycle, ideally immediately after creation.
  • Use Deep Freeze When Necessary: If you need to ensure that nested objects are also immutable, use a deep freeze implementation.
  • Consider Performance: Deep freezing can be computationally expensive, especially for large objects.
  • Strict Mode Awareness: Remember that Object.freeze throws errors in strict mode when modifications are attempted. Ensure your code handles these errors gracefully or operates in a non-strict environment where modifications are silently ignored.

Interview Tip

Be prepared to discuss the differences between Object.freeze, Object.seal, and Object.preventExtensions. Also, understand the concept of shallow vs. deep immutability. Explain how you might implement a deep freeze function and the trade-offs involved.

When to use them

Use Object.freeze() when you need to guarantee that an object's properties will not change after initialization. This is particularly useful for configuration objects, data models in functional programming, and protecting data integrity in shared modules.

Memory footprint

Object.freeze() itself doesn't directly increase the memory footprint significantly. The existing memory occupied by the object remains the same. However, if you are creating a large number of frozen objects, the accumulated memory usage will increase. Deep freezing increases the memory usage because it involves recursively iterating and freezing nested objects.

Alternatives

  • Object.seal(): Prevents adding or deleting properties but allows modifying existing properties.
  • Object.preventExtensions(): Prevents adding new properties but allows deleting and modifying existing properties.
  • Immutability Libraries: Libraries like Immutable.js provide persistent data structures that are inherently immutable. These libraries offer more sophisticated immutability features and performance optimizations.

Pros

  • Data Integrity: Prevents accidental modification of data.
  • Predictability: Makes code easier to reason about and debug.
  • Functional Programming: Supports functional programming paradigms.
  • Security: Can protect against certain types of attacks by preventing modification of critical objects.

Cons

  • Shallow Freeze: Only freezes the object itself, not nested objects.
  • Performance Overhead: Deep freezing can be computationally expensive.
  • Error Handling: Modifying frozen objects can lead to errors in strict mode.
  • Debugging: Requires careful planning to ensure that immutability is properly implemented and maintained.

FAQ

  • What is the difference between Object.freeze(), Object.seal(), and Object.preventExtensions()?

    • Object.freeze(): Prevents adding, deleting, or modifying properties.
    • Object.seal(): Prevents adding or deleting properties but allows modifying existing properties.
    • Object.preventExtensions(): Prevents adding new properties but allows deleting and modifying existing properties.
  • Is Object.freeze() recursive?

    No, Object.freeze() is not recursive. It only freezes the object itself, not any nested objects. You need to implement a deep freeze function to recursively freeze nested objects.
  • What happens if I try to modify a frozen object in strict mode?

    In strict mode, attempting to modify a frozen object will throw a TypeError. In non-strict mode, the modification will fail silently.