Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a read only property(element.classList) can be modified or assigned to some other value in javascript?

Tags:

javascript

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>

enter image description here

Above is a screenshot of chrome devtools with values modified.

I read on MDN that element.classList is read only property but can be modified by add() etc.

I assigned it to some other array and that is working too.

In other cases, whenever I tried to modify/assign read only property, it always gave typeError.

like image 654
Ajay Tanwar Avatar asked Jan 08 '17 12:01

Ajay Tanwar


People also ask

How does classList work in JavaScript?

The Element.classList is a read-only property that returns a live DOMTokenList collection of the class attributes of the element. This can then be used to manipulate the class list. Using classList is a convenient alternative to accessing an element's list of classes as a space-delimited string via element.className .

What does the element classList toggle () method do?

toggle() The toggle() button is used for toggling classes to the element. It means adding a new class or removing the existing classes.

How does classList toggle work?

toggle() will add the CSS class if it does not exist in the classList array and return true . If the CSS class exists, the method will remove the class and return false . The classList. toggle() method supports adding and removing CSS classes whether they exist or not in your array with shorter lines of code.


1 Answers

Very good question.

I did not originally know the exact answer to your question, but I'm not surprised as much by the behaviour. The spec defines the minimum that all compliant useragents (browsers) must implement. It also defines all the features that developers can expect and rely on when targeting compliant useragents (browsers). It's up to the browsers to add additional non-standard features.

This means that all browsers have to implement a get property called classList. Developers should only expect a get property to be available in browsers. Browsers might think it's convenient for developers to have a set function implemented too. It's fairly common for browsers to do this kind of thing. Sometimes this kind of features gets added to a newer version of the standard, sometimes it never makes it because the standard committee disagrees with the purity of the feature.

Sometimes non-standard features get deprecated and even removed, which although takes years - is a good reason for developers to not rely on non standard features when other standard features can achieve the same goal (for example, the property className can be used to override the classList).

But how is it done technically after all?

Chrome implements this in a very clever way (might be originally WebKit). It applies an attribute PutForwards to the definition of classList.

This allows the property to be defined as readonly, but when assigned a value, one of the properties of the object gets assigned instead, not the entire object. In this case, the child property name is value.

So, the code document.body.classList = '123';
is the same as document.body.classList.value = '123';

You can confirm the object was not replaced by running the following in Chrome console

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
);

The definition of classList in Chromium source code

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

can be found at: https://github.com/chromium/chromium/blob/4141778eb03a31a20d9e109f74faf2f756b4a8c4/third_party/blink/renderer/core/dom/element.idl#L37

Note how this is different from the definition in the spec

[SameObject] readonly attribute DOMTokenList classList;`  

which can be found at https://www.w3.org/TR/dom/#element

And the test in the source code that explains the relation between the attribute and the ability to override the readonly property in its comment

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

can be found at: https://github.com/chromium/chromium/blob/f18e79d901f56154f80eea1e2218544285e62623/third_party/WebKit/LayoutTests/fast/dom/HTMLElement/resources/class-list.js#L13

like image 144
Meligy Avatar answered Oct 27 '22 00:10

Meligy