为什么在更新 DOM 元素的样式属性时对象传播失败但 Object.assign 成功?
Why does object spread fail but Object.assign succeeds when updating a DOM element's style attribute?
上下文
当使用 vanilla js 更新 DOM 元素的 style
属性时,为什么对象传播失败而 Object.assign
成功?
例如,在包含的代码片段中,objectAssignDirect
和 objectAssignIndirect
正确设置了 background-color
而 objectSpread
错误地重置了结果 div
的 background-color
.
问题
- 为什么会这样? (这是由于克隆问题还是继承属性等属性没有被复制?)
- 有没有办法通过对象传播来复制
Object.assign
所需的行为?
参考资料
有几个比较 Object.assign
和对象传播的讨论,但 none 似乎解决了这种奇怪的行为:
// 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>
直接分配给元素的 .style
标签不会导致样式改变。相反,它会默默地失败:
foo.style = { backgroundColor: 'green' };
console.log(foo.style.backgroundColor);
<div id="foo">foo</div>
您必须分配给现有 .style
(现有 CSSStyleDeclaration)的 属性 才能调用导致 DOM 更改的 setter。您不能尝试用其他东西完全重新分配 style
属性,因为这样您就不会在 CSSStyleDeclaration 上调用特殊的 setter。执行 { ...myElement.style }
会创建一个新的普通对象,而不是 CSSStyleDeclaration。
Object.assign
适用于您的两个原始代码段,因为它会调用 setters.
这种行为的另一个例子:
const obj = Object.create({ style: {
set someProp(arg) {
console.log('Setter invoked; changing DOM');
}
}});
console.log('Invokes setter:');
obj.style.someProp = 'newVal';
console.log("Doesn't invoke setter:");
obj.style = { someProp: 'newVal' };
Why does this happen?
style
是只读的 属性,不能赋新值。
element.style = { ...element.style, backgroundColor: 'green' };
创建 element.style
、adds/updates 和 属性 backgroundColor
的浅表副本并将副本分配回 element.style
。由于这个原因它失败了,因为你不能分配 element.style
一个新值。
Object.assign(element.style, { backgroundColor: 'green' });
将第二个参数中的每个 property/value 对分配给 element.style
。它不会创建 element.style
的副本,但会改变 element.style
对象。
Is there a way to replicate Object.assign
's desired behaviour with object spread?
不,对象扩展仅用于对象文字,这将始终导致创建新对象。您不能使用对象传播更新现有对象。
上下文
当使用 vanilla js 更新 DOM 元素的 style
属性时,为什么对象传播失败而 Object.assign
成功?
例如,在包含的代码片段中,objectAssignDirect
和 objectAssignIndirect
正确设置了 background-color
而 objectSpread
错误地重置了结果 div
的 background-color
.
问题
- 为什么会这样? (这是由于克隆问题还是继承属性等属性没有被复制?)
- 有没有办法通过对象传播来复制
Object.assign
所需的行为?
参考资料
有几个比较 Object.assign
和对象传播的讨论,但 none 似乎解决了这种奇怪的行为:
// 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>
直接分配给元素的 .style
标签不会导致样式改变。相反,它会默默地失败:
foo.style = { backgroundColor: 'green' };
console.log(foo.style.backgroundColor);
<div id="foo">foo</div>
您必须分配给现有 .style
(现有 CSSStyleDeclaration)的 属性 才能调用导致 DOM 更改的 setter。您不能尝试用其他东西完全重新分配 style
属性,因为这样您就不会在 CSSStyleDeclaration 上调用特殊的 setter。执行 { ...myElement.style }
会创建一个新的普通对象,而不是 CSSStyleDeclaration。
Object.assign
适用于您的两个原始代码段,因为它会调用 setters.
这种行为的另一个例子:
const obj = Object.create({ style: {
set someProp(arg) {
console.log('Setter invoked; changing DOM');
}
}});
console.log('Invokes setter:');
obj.style.someProp = 'newVal';
console.log("Doesn't invoke setter:");
obj.style = { someProp: 'newVal' };
Why does this happen?
style
是只读的 属性,不能赋新值。
element.style = { ...element.style, backgroundColor: 'green' };
创建 element.style
、adds/updates 和 属性 backgroundColor
的浅表副本并将副本分配回 element.style
。由于这个原因它失败了,因为你不能分配 element.style
一个新值。
Object.assign(element.style, { backgroundColor: 'green' });
将第二个参数中的每个 property/value 对分配给 element.style
。它不会创建 element.style
的副本,但会改变 element.style
对象。
Is there a way to replicate
Object.assign
's desired behaviour with object spread?
不,对象扩展仅用于对象文字,这将始终导致创建新对象。您不能使用对象传播更新现有对象。