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

Merging Objects with Object.assign()

Learn how to effectively merge properties from multiple source objects into a single target object using JavaScript's Object.assign(). This example covers basic usage, handling conflicts, and creating deep copies.

Basic Object Merging

Object.assign() copies the values of all enumerable own properties from one or more source objects to a target object. It returns the modified target object. In this basic example, we merge the source object into the target object. Notice that if a property exists in both the target and source, the source's value overwrites the target's value (e.g., 'b'). The original target object is modified.

// Example 1: Basic merging
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

console.log(target); // Output: { a: 1, b: 4, c: 5 }
console.log(returnedTarget === target); // Output: true

Merging Multiple Sources

Object.assign() can accept multiple source objects. Properties are copied in the order they are listed. Here, we merge obj1, obj2, and obj3 into a new object. We use an empty object {} as the first argument to create a new object, ensuring that none of the original objects are modified. This is often the preferred approach to avoid unexpected side effects.

// Example 2: Merging multiple sources
const obj1 = { a: 1 };
const obj2 = { b: 2 };
const obj3 = { c: 3 };

const merged = Object.assign({}, obj1, obj2, obj3);

console.log(merged); // Output: { a: 1, b: 2, c: 3 }
console.log(obj1); // Output: { a: 1 } (original object is not modified)

Handling Overlapping Properties

When multiple source objects have the same property, the value from the rightmost source object takes precedence. In this example, sourceObj1's c value (4) is initially copied, but then sourceObj2's c value (5) overwrites it. The b property from sourceObj1 overwrites the initial value in targetObj.

// Example 3: Overlapping properties
const targetObj = { a: 1, b: 2 };
const sourceObj1 = { b: 3, c: 4 };
const sourceObj2 = { c: 5, d: 6 };

const finalObj = Object.assign(targetObj, sourceObj1, sourceObj2);

console.log(finalObj); // Output: { a: 1, b: 3, c: 5, d: 6 }

Concepts Behind Object.assign()

Object.assign() is a shallow copy operation. This means that if the source object contains nested objects, only the references to those nested objects are copied, not the nested objects themselves. Changes to the nested objects in the target object will also affect the original source objects (and vice-versa).

Real-Life Use Case

A common use case is merging configuration objects. Imagine you have default settings for a component and want to allow users to override these settings. Object.assign() is perfect for this.

// Example: Configuration merging
const defaultSettings = {
  color: 'blue',
  fontSize: 16,
  fontFamily: 'Arial'
};

const userSettings = {
  color: 'red',
  fontWeight: 'bold'
};

const finalSettings = Object.assign({}, defaultSettings, userSettings);

console.log(finalSettings); // Output: { color: 'red', fontSize: 16, fontFamily: 'Arial', fontWeight: 'bold' }

Best Practices

  • Avoid Modifying the Target Object Directly: It's generally better to start with an empty object as the target to prevent unintended side effects on the original objects. This creates a new, independent object.
  • Understand Shallow Copying: Be aware that nested objects are copied by reference. For deep copies, consider using techniques like JSON.parse(JSON.stringify(obj)) (with limitations) or libraries like Lodash's _.cloneDeep().

Interview Tip

Be prepared to discuss the difference between shallow and deep copying, and when Object.assign() is appropriate versus when a deep copy is necessary. Also, know that Object.assign() only copies enumerable and own properties.

When to use them

Use Object.assign() when you need to merge simple objects and don't have nested objects or arrays that require deep copying. It's efficient for copying configuration settings or applying overrides.

Memory Footprint

The memory footprint of Object.assign() is relatively low, especially for shallow copies. Creating deep copies, using methods like JSON.parse(JSON.stringify(obj)), will consume more memory, particularly for large objects.

Alternatives

  • Spread Operator (...): The spread operator provides a more concise syntax for merging objects: const merged = { ...obj1, ...obj2, ...obj3 }; It also performs a shallow copy.
  • Lodash's _.assign() and _.merge(): Lodash provides more robust merging capabilities, including deep merging with _.merge().

Pros

  • Simple Syntax: Easy to understand and use.
  • Native Implementation: Built into JavaScript, no external libraries required for basic usage.
  • Efficient for Shallow Copies: Performs well for simple object merging.

Cons

  • Shallow Copy: Does not perform deep copies of nested objects.
  • Only Copies Enumerable Properties: Ignores non-enumerable properties.
  • Modifies Target Object: Can lead to unexpected side effects if the target object is not a new object.

FAQ

  • Does Object.assign() create a new object?

    Object.assign() modifies the target object passed as the first argument. To create a new object, pass an empty object ({}) as the first argument.
  • What happens if a source object has a property with the same name as the target object?

    The value of the property from the source object will overwrite the value of the corresponding property in the target object.
  • How can I perform a deep copy of an object?

    Object.assign() performs a shallow copy. For deep copies, you can use JSON.parse(JSON.stringify(obj)) (with limitations regarding functions and circular references) or utilize a library like Lodash (_.cloneDeep()).