Master object manipulation using object.assign, object.freeze, and proxies: Advanced Javascript

Vamsi Krishna Kodimela
Angular Simplified
Published in
4 min readJan 11, 2024

Object manipulation is one of the key concepts used by almost every JavaScript developer. While basic techniques like property assignment and object creation are essential, JavaScript offers more advanced methods for working with objects, providing flexibility, control, and immutability.

In this story, we’ll explore three powerful tools: Object.assign, Object.freeze, and proxies.

Object.assign: The Master of Merging

Object.assign is a built-in method that allows you to merge properties from multiple objects into a target object. It’s highly versatile and serves various purposes:

  • Combining objects: Create new objects with properties from multiple sources.
  • Cloning objects: Create shallow copies of objects, retaining their structure and values.
  • Default values: Set default properties for objects, ensuring they always have certain values.

Syntax:

Object.assign(target, source1, source2, ...);

Key Points:

  • Overwrites existing properties in the target object with those from the source objects.
  • Does not mutate the source objects themselves.
    Returns the modified target object.
  • Creates shallow copies, meaning nested objects are not copied recursively.

Sample Snippet:

// Merging objects
const person = { name: "John" };
const address = { city: "New York" };
const combined = Object.assign({}, person, address); // { name: "John", city: "New York" }

// Cloning objects
const original = { age: 30 };
const clone = Object.assign({}, original);

// Default values
function createUser(name) {
return Object.assign({ age: 25, active: true }, { name });
}

Object.freeze: The Guardian of Immutability

Object.freeze is a built-in method that prevents further modifications to an object and its properties. Once an object is frozen, you can’t:

  • Add new properties.
  • Remove existing properties.
  • Change the values of existing properties.

Embracing Immutability

In JavaScript, objects are mutable by default, meaning their properties can be changed after creation. While mutability offers flexibility, it can also lead to unexpected side effects and make state management challenging.

Syntax:

Object.freeze(object);

Key Points:

  • Makes an object and its properties immutable.
  • Recursively freezes nested objects as well.
  • Returns the frozen object.
  • Can be used to create constant objects with fixed values.
  • Useful for preventing accidental changes and promoting predictable behavior.

Sample Snippet:

const config = Object.freeze({ apiUrl: "https://api.example.com" });
// config.apiUrl = "https://new-api.example.com"; // Error: Cannot assign to read-only property 'apiUrl'

const user = { name: "Alice", age: 30 };
Object.freeze(user);
user.age = 31; // No effect, the object is frozen

Benefits of Mutability:

  • Predictability: Ensures a consistent state and helps avoid unexpected side effects.
  • Reliability: Makes code more robust and less prone to errors.
  • Performance: This can improve performance in certain cases, as JavaScript engines can optimize operations on immutable data.

Proxies: The Ultimate Object Manipulators

Proxies are the most advanced object manipulation feature in JavaScript. They offer a mechanism to intercept and redefine fundamental object operations like property access, assignment, and method calls. This opens up a realm of possibilities for custom behavior, dynamic data handling, and advanced programming patterns.

Key Concepts:

  • Traps: Proxies use traps to intercept operations and potentially modify their behavior. Common traps include get, set, has, deleteProperty, and more.
  • Handler: The proxy object defines a handler object that contains the traps.
  • Redirection: When an operation is performed on the proxy object, it’s redirected to the corresponding trap in the handler.

Creating a Proxy:

const handler = {
get: (target, prop) => {
// Custom logic for property access
},
set: (target, prop, value) => {
// Custom logic for property assignment
},
// ...other traps
};

const proxy = new Proxy(targetObject, handler);

Use cases:

  • Validation: Enforce data validation rules before property assignments.
  • Lazy Loading: Retrieve properties from external sources only when accessed.
  • Access Logging: Track property access for debugging or monitoring.
  • Custom Data Structures: Create objects with unique behaviors, like self-validating forms or reactive data stores
  • Observability: Implement reactive programming patterns with automatic updates based on data changes.
  • Virtual DOM: Optimize rendering in UI frameworks by creating virtual representations of the DOM.
  • Metaprogramming: Manipulate code itself for dynamic code generation or optimization.

Caution:

- Proxies are powerful but can introduce complexity. Use them judiciously when simpler approaches won’t suffice.
- Consider performance implications, as proxies can add overhead.
Test thoroughly to ensure custom behavior works as expected.

--

--