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:
- Own Properties: Properties that belong directly to
the object itself, rather than being inherited through the prototype
chain.
Object.assign()ignores properties on the prototype chain. - Enumerable Properties: Properties with their
internal
[[Enumerable]]flag set totrue. Standard object properties created via standard assignment or object literals are enumerable by default. Hidden or non-enumerable properties (such as those defined viaObject.defineProperty()withenumerable: false) are ignored during the copy process.
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 copiedSummary of Rules
- Copied: Enumerable own string properties, enumerable own Symbol properties, evaluated getter results.
- Ignored: Inherited properties from prototype chains, non-enumerable properties (string or Symbol).
- Behavior: Mutates the target object, invokes target setters, and performs shallow reference copies for nested objects.