如何在javascript中修改只读属性(element.classList)或将其分配给其他值?

问题描述 投票:6回答:2

window.addEventListener('keydown',function(e) {
    const key= document.querySelector(`div[data-key='${e.keyCode}']`);
    console.log(key.className);
    console.log(key.classList);
    key.classList=['ajay','dish'];
}
<div data-key="65" class="key ajay">
			<kbd>A</kbd>
</div>

以上是chrome devtools的屏幕截图,其值已修改。

我在MDN上读到element.classList是只读属性,但可以通过add()等进行修改。

我将它分配给其他阵列,这也是有效的。

在其他情况下,每当我尝试修改/分配只读属性时,它总是给出typeError

javascript
2个回答
1
投票

非常好的问题。

我原本不知道你问题的确切答案,但我对这种行为并不感到惊讶。规范定义了所有合规用户(浏览器)必须实现的最小值。它还定义了开发人员在针对合规用户(浏览器)时可以期待和依赖的所有功能。由浏览器添加其他非标准功能。

这意味着所有浏览器都必须实现名为getclassList属性。开发人员应该只期望在浏览器中提供get属性。浏览器可能认为开发人员也可以方便地实现set功能。浏览器做这种事情是相当普遍的。有时,这种功能会被添加到标准的新版本中,有时它永远不会成功,因为标准委员会不同意该功能的纯度。

有时非标准功能会被弃用甚至删除,虽然需要数年时间 - 这是开发人员在其他标准功能可以实现相同目标时不依赖非标准功能的一个很好的理由(例如,属性className可用于覆盖classList)。

But how is it done technically after all?

Chrome以非常聪明的方式实现了这一点(可能最初是WebKit)。它将属性PutForwards应用于classList的定义。

这允许将属性定义为readonly,但是当赋值时,将分配对象的一个​​属性,而不是整个对象。在这种情况下,子属性名称是value

所以,代码document.body.classList = '123';document.body.classList.value = '123';相同

您可以通过在Chrome控制台中运行以下内容来确认未替换该对象

const body = document.body;
const oldClassList = body.classList;
const oldValue = body.classList.value;
body.classList = "new-class";
const newClassList = body.classList;
const newValue = body.classList.value;
console.log(
  "classList changed:", oldClassList !== newClassList, // false
  "value changed:", oldValue !== newValue // true
);

Chromium源代码中classList的定义

[Affects=Nothing, SameObject, PerWorldBindings, PutForwards=value] readonly attribute DOMTokenList classList;

可以在:https://github.com/chromium/chromium/blob/4141778eb03a31a20d9e109f74faf2f756b4a8c4/third_party/blink/renderer/core/dom/element.idl#L37找到

请注意这与规范中的定义有何不同

[SameObject] readonly attribute DOMTokenList classList;`  

可以在https://www.w3.org/TR/dom/#element找到

源代码中的测试解释了属性与覆盖其注释中readonly属性的能力之间的关系

// Even though classList is readonly, PutForwards=value means that its value is forwarded.

可以在:https://github.com/chromium/chromium/blob/f18e79d901f56154f80eea1e2218544285e62623/third_party/WebKit/LayoutTests/fast/dom/HTMLElement/resources/class-list.js#L13找到


0
投票

只需使用.add()方法


    const key= document.querySelector(`div[data-key='${e.keyCode}']`);
    key.classList.add("your class");


© www.soinside.com 2019 - 2024. All rights reserved.