Object.assign
This lesson explains Object.assign with clear examples, use cases, and best practices so you can use modern JavaScript confidently in real projects.
ES6+ Object.assign Overview
Object.assign() copies enumerable own properties from
one or more source objects into a target object. It is commonly
used to merge objects, clone objects, and update state in modern
JavaScript applications.
Although the object spread operator is now widely used,
Object.assign() remains important because it mutates
the target object and is still common in older codebases and
certain utility patterns.
| Feature | Description |
| Introduced In | ES6 (ECMAScript 2015) |
| Syntax | Object.assign(target, ...sources) |
| Behavior | Copies properties into the target object |
| Return Value | The modified target object |
| Copy Type | Shallow copy |
| Common Uses | Merging, cloning, defaults, state updates |
Basic Object.assign Example
const target = {
name: "Alex"
};
const source = {
role: "admin",
active: true
};
const result =
Object.assign(
target,
source
);
console.log(result);
console.log(target);
Properties from source are copied into
target, and the same modified target object is
returned.
How Object.assign Works
Object.assign() loops through each source object and
copies its own enumerable properties into the target. If the same
key exists in multiple sources, the later source wins.
| Step | Description | Example |
| Choose Target | Select the object to receive properties. | const target = { } |
| Add Sources | Pass one or more source objects. | source1, source2 |
| Copy Properties | Enumerable own keys are copied. | role: "admin" |
| Resolve Conflicts | Later sources override earlier ones. | theme: "dark" |
| Return Target | Modified target is returned. | result |
Merge Multiple Objects
const defaults = {
theme: "light",
language: "en",
notifications: false
};
const userPrefs = {
theme: "dark"
};
const session = {
notifications: true
};
const settings =
Object.assign(
{},
defaults,
userPrefs,
session
);
console.log(settings);
Passing an empty object as the target is a common way to merge
multiple sources into a new object without mutating the originals.
Clone an Object
const original = {
id: 1,
name: "Sam",
active: true
};
const copy =
Object.assign({}, original);
copy.name = "Updated Name";
console.log(original.name);
console.log(copy.name);
Object.assign({}, obj) creates a shallow
clone of the top-level properties in an object.
Update Object Properties
const user = {
id: 10,
name: "Alex",
role: "viewer"
};
Object.assign(user, {
role: "editor",
lastLogin: "2026-06-27"
});
console.log(user);
You can update an existing object by using it as the target and
passing new properties in a source object.
Later Sources Override Earlier Ones
const base = {
status: "draft",
theme: "light"
};
const overrideA = {
theme: "dark"
};
const overrideB = {
theme: "blue",
status: "published"
};
const result =
Object.assign(
{},
base,
overrideA,
overrideB
);
console.log(result);
When multiple sources define the same property, the value from the
last source is used.
Understand Shallow Copying
const original = {
title: "Dashboard",
settings: {
theme: "light"
}
};
const copy =
Object.assign({}, original);
copy.settings.theme = "dark";
console.log(
original.settings.theme
);
console.log(
copy.settings.theme
);
Object.assign() performs a shallow copy. Nested objects
are still shared by reference, so changing nested data affects both
objects unless you clone deeper levels too.
Apply Default Values
function createProfile(
options = {}
) {
const defaults = {
theme: "light",
language: "en",
notifications: true
};
return Object.assign(
{},
defaults,
options
);
}
const profile =
createProfile({
language: "fr"
});
console.log(profile);
Default values are a common use case. User-provided options override
defaults while missing keys keep their fallback values.
Object.assign vs Spread Operator
const base = {
id: 1,
name: "Alex"
};
const update = {
role: "admin"
};
const withAssign =
Object.assign(
{},
base,
update
);
const withSpread = {
...base,
...update
};
console.log(withAssign);
console.log(withSpread);
| Feature | Object.assign() | Object Spread |
| Syntax | Object.assign(target, source) | { ...source } |
| Readability | Function-based | Often cleaner for merges |
| Mutation | Can mutate target directly | Creates new object literal |
| Common Use | Utilities and legacy code | Modern immutable updates |
Common Object.assign Use Cases
- Merging configuration and user preference objects.
- Creating shallow clones of plain objects.
- Updating existing objects with new properties.
- Applying default options in utility functions.
- Combining API response fragments.
- Copying props in older React or Redux patterns.
- Building objects from multiple dynamic sources.
Object.assign Best Practices
- Use an empty object as the target when you want a new merged object.
- Remember that
Object.assign() performs a shallow copy. - Prefer spread syntax for simple immutable merges in modern code.
- Place defaults first and overrides later.
- Avoid mutating shared objects unintentionally.
- Use deep cloning when nested objects must be independent.
- Keep source object order intentional when keys may overlap.
Common Object.assign Mistakes
- Mutating the original object when a clone was intended.
- Expecting nested objects to be deeply copied.
- Forgetting that later sources override earlier ones.
- Passing
null or undefined as the target. - Assuming inherited properties are copied.
- Using
Object.assign() for arrays when merge behavior is unexpected. - Overwriting important defaults by passing sources in the wrong order.
Key Takeaways
Object.assign() copies properties into a target object. - It returns the modified target object.
- Later sources override earlier ones for duplicate keys.
- It performs a shallow copy, not a deep clone.
- Use it to merge, clone, and apply defaults in object-based workflows.
Pro Tip
To merge without mutating originals, use
Object.assign({}, defaults, options) or the
equivalent spread pattern
{ ...defaults, ...options }.