简体   繁体   中英

Using Symbol as DOM / HTMLElement attributes

In general custom HTML element attributes are discouraged but in some cases one have the choice between either having a collection of nodes that one saves and traverse for comparison or setting a property. As for the former that is often enough not a good choice.

Usually I would use dataset for this, but what if that is not a good option due to the script being used on any site where one have no control of what that site itself does?

Say one want to tag all <video> elements with a custom status property could one use Symbol() attached directly to the element? I have tested using Symbol() on dataset but it seems to be lost sometimes. As in: I can set it, log it, next call it is sometimes there, sometimes not. (Which also makes a use-case harder to make) Not sure why. Might have something to do with it being a media element? Symbol() is perhaps not valid as "dataset property name" ?

Question the is if it is OK to set it directly on the element?

const symbol = Symbol.for("test");
// in some function:

// instead of:
some_element.dataset[symbol] = "foo";
// do:
some_element[symbol] = "foo";

Have not had any trouble with the latter (as in property disappearing).

Or could one perhaps use something like:

Object.defineProperty(element, symbol, {
        readonly: true,
        value: "foo"
});

If your worry is that the site you have no control over could theoretically modify the data attribute - the same could occur with a symbol if the other site was really intent on breaking things.

 const element = document.querySelector('div'); // Your code const symbol = Symbol.for("test"); element[symbol] = "foo"; // Site's code const [sym] = Object.getOwnPropertySymbols(element); element[sym] = "bar"; // Your code, later console.log(element[symbol]);
 <div></div>

or, the site itself could use Symbol.for too.

 const element = document.querySelector('div'); // Your code const symbol = Symbol.for("test"); element[symbol] = "foo"; // Site's code element[Symbol.for('test')] = "bar"; // Your code, later console.log(element[symbol]);
 <div></div>

Defining the property as readonly could work, but it'd also make you unable to alter the property later, which you might find would eventually be a problem.

A better solution would be to, instead of putting a property onto the object, to create your own collection that associates the elements with your custom values. If your own collection is scoped to only your own script (like with an IIFE), it'll then be impossible for other scripts to interfere with. This is a great place for a WeakMap. For example:

 // Your code (() => { const map = new WeakMap(); const element = document.querySelector('div'); // Set the value: map.set(element, 'foo'); // Retrieve the value: console.log(map.get(element)); })();
 <div></div>

The WeakMap values will continue to work and be unmodifiable by outside sources as long as the elements still exist in memory.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM