How Object.assign Copies Enumerable Own Properties

In JavaScript, Object.assign() is a built-in method designed to copy the values of all enumerable own properties from one or more source objects to a target object. It modifies the target object directly and returns the updated target. Understanding how it interacts with property attributes, prototypes, and references is essential for managing object state and immutability effectively.

What Are Enumerable Own Properties?

To understand how Object.assign() operates, two property classifications must be distinguished:

Core Mechanics of Object.assign

1. Shallow Copying

Object.assign() creates a shallow copy, not a deep clone. When a property value is a primitive (such as a string, number, or boolean), the value is copied directly. If a property value is an object or an array, Object.assign() copies only the reference to that object. Consequently, mutating a nested object in the target will also mutate the original object in the source.

2. Getters and Setters Invocation

Object.assign() uses the [[Get]] operation on the source object and the [[Set]] operation on the target object. This means: * If the source object has a getter, it executes the getter function and assigns the returned value to the target. * If the target object has a setter for that property key, it triggers the setter rather than defining a new property descriptor.

3. Overwriting Order

Properties are assigned in the order the source objects are passed as arguments. If multiple source objects contain the same property key, the value from the last source object in the argument list will overwrite the earlier ones.

4. Handling Symbol Properties

Object.assign() copies both string-keyed and Symbol-keyed enumerable own properties.

Code Example

const target = { a: 1, b: 2 };

const source1 = {
  b: 42, // Will overwrite target.b
  nested: { count: 10 } // Copied by reference
};

const source2 = {
  [Symbol('id')]: 101 // Enumerable Symbol, will be copied
};

// Define a non-enumerable property (will be ignored)
Object.defineProperty(source1, 'hidden', {
  value: 'secret',
  enumerable: false
});

const result = Object.assign(target, source1, source2);

console.log(result);
// Output includes: a: 1, b: 42, nested: { count: 10 }, Symbol(id): 101
// 'hidden' is not copied

Summary of Rules