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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With