Copying and merging objects
You can use spread syntax to merge multiple objects into one new object.
const obj1 = { foo: "bar", x: 42 };
const obj2 = { bar: "baz", y: 13 };
const mergedObj = { ...obj1, ...obj2 };
A single spread creates a shallow copy of the original object (but without non-enumerable properties and without copying the prototype), similar to copying an array.
const clonedObj = { ...obj1 };
Overriding properties
When one object is spread into another object, or when multiple objects are spread into one object, and properties with identical names are encountered, the property takes the last value assigned while remaining in the position it was originally set.
const obj1 = { foo: "bar", x: 42 };
const obj2 = { foo: "baz", y: 13 };
const mergedObj = { x: 41, ...obj1, ...obj2, y: 9 };
Conditionally adding properties to an object
You can make an element present or absent in an object literal, depending on a condition, using a conditional operator.
const isSummer = false;
const fruits = {
apple: 10,
banana: 5,
...(isSummer ? { watermelon: 30 } : {}),
};
The case where the condition is false
is an empty object, so that nothing gets spread into the final object. Note that this is different from the following:
const fruits = {
apple: 10,
banana: 5,
watermelon: isSummer ? 30 : undefined,
};
In this case, the watermelon
property is always present and will be visited by methods such as Object.keys()
.
Because primitives can be spread into objects as well, and from the observation that all falsy values do not have enumerable properties, you can simply use a logical AND operator:
const isSummer = false;
const fruits = {
apple: 10,
banana: 5,
...(isSummer && { watermelon: 30 }),
};
In this case, if isSummer
is any falsy value, no property will be created on the fruits
object.
Comparing with Object.assign()
Note that Object.assign()
can be used to mutate an object, whereas spread syntax can't.
const obj1 = { foo: "bar", x: 42 };
Object.assign(obj1, { x: 1337 });
console.log(obj1);
In addition, Object.assign()
triggers setters on the target object, whereas spread syntax does not.
const objectAssign = Object.assign(
{
set foo(val) {
console.log(val);
},
},
{ foo: 1 },
);
const spread = {
set foo(val) {
console.log(val);
},
...{ foo: 1 },
};
You cannot naively re-implement the Object.assign()
function through a single spreading:
const obj1 = { foo: "bar", x: 42 };
const obj2 = { foo: "baz", y: 13 };
const merge = (...objects) => ({ ...objects });
const mergedObj1 = merge(obj1, obj2);
const mergedObj2 = merge({}, obj1, obj2);
In the above example, the spread syntax does not work as one might expect: it spreads an array of arguments into the object literal, due to the rest parameter. Here is an implementation of merge
using the spread syntax, whose behavior is similar to Object.assign()
, except that it doesn't trigger setters, nor mutates any object:
const obj1 = { foo: "bar", x: 42 };
const obj2 = { foo: "baz", y: 13 };
const merge = (...objects) =>
objects.reduce((acc, cur) => ({ ...acc, ...cur }));
const mergedObj1 = merge(obj1, obj2);