When using vanilla js to update a DOM element's style
attribute, why does object spread fail to update whilst Object.assign
succeeds?
E.g., in the included code snippet, objectAssignDirect
and objectAssignIndirect
correctly set background-color
whilst objectSpread
incorrectly resets the result div
's background-color
.
Object.assign
's desired behaviour with object spread?There are several discussions comparing Object.assign
and object spread but none seem to address this strange behaviour:
// Using `Object.assign` directly.
const objectAssignDirect = () => {
Object.assign(document.querySelector('.myClass').style, { backgroundColor: 'red' }); // Works.
console.log('Result should be red');
}
// Updating using `Object.assign` with variable.
const objectAssignIndirect = () => {
const myElement = document.querySelector('.myClass')
Object.assign(myElement.style, { backgroundColor: 'blue' }); // Works.
console.log('Result should be blue');
}
// Using object spread with variable.
const objectSpread = () => {
const myElement = document.querySelector('.myClass')
myElement.style = { ...myElement.style, backgroundColor: 'green' }; // Fails.
console.log('Result should be green');
}
body {
font-size: 2em;
}
.myClass {
width: 100%;
height: 50px;
background-color: black;
color: white;
border: 4px solid black;
text-align: center;
padding: 10px;
}
button {
padding: 15px;
margin: 30px;
color: white;
border-radius: 20px;
}
.red {
background-color: red;
}
.blue {
background-color: blue;
}
.green {
background-color: green;
}
<div style="display:flex;justify-content:center;">
<button class="red" onclick="objectAssignDirect();">Use <code>Object.assign</code> directly</button>
<button class="blue" onclick="objectAssignIndirect();">Use <code>Object.assign</code> indirectly</button>
<button class="green" onclick="objectSpread();">Use object spread</button>
</div>
<div class="myClass">Result</div>
Why does this happen?
style
is a read-only property, and cannot be assigned to a new value.
element.style = { ...element.style, backgroundColor: 'green' };
Creates a shallow copy of element.style
, adds/updates the property backgroundColor
and assigns the copy back to element.style
. For this reason it fails, because you cannot assign element.style
a new value.
Object.assign(element.style, { backgroundColor: 'green' });
Assigns each property/value pair in the second argument to element.style
. It does not create a copy of element.style
, but mutates the element.style
object.
Is there a way to replicate
Object.assign
's desired behaviour with object spread?
No, object spread is used only in object literals, which will always result in a new object being created. You cannot update an existing object using object spread.