Metadata v javascriptu
V Clojure symboly a kolekce podporují tzv. metadata. Slouží k anotování dat a důležité je, že nejsou součástí hodnoty daného objektu. Občas by se mi to hodilo i ve světě javascriptu.
Cílem je mít možnost definovat na objekt metadata, která lze kdykoliv získat a zároveň která nejsou "enumerable", tj. nepropadnou do JSON.stringify
, Object.entries
, ...
apod.
Nejde o žádnou vědu - javascript nabízí statickou funkci Object.defineProperty
, která při správné konfiguraci dělá přesně to, co potřebuju.
Začnu tím, že vlastnost meta
bude definována skrz symbol, takže se k ní není možné jednoduše dostat zvenku.
Důležitá je ta konfigurace, kdy value
nepotřebuje další komentrář, writable
umožňuje hodnotu metadat měnit, configurable
ji naopak dovoluje smazat a enumerable
ji dělá "tajnou".
// meta.js
const metaProp = Symbol.for("meta");
export function withMeta(m, x) {
Object.defineProperty(x, metaProp, {
value: m,
writable: true,
configurable: true,
enumerable: false,
});
return x;
}
export function meta(x) {
return x[metaProp];
}
export function alterMeta(x, f) {
x[metaProp] = f(x[metaProp]);
return x;
}
export function resetMeta(x) {
delete x[metaProp];
return x;
}
Použití je následovné:
const a = withMeta({ version: 1 }, { foo: "bar" });
// { foo: "bar" }
Object.entries(a);
// [["foo", "bar"]]
meta(a);
// { version: 1 }
const incVersion = ({ version, ...rest }) => ({
version: version + 1,
...rest
});
alterMeta(a, incVersion)
// { foo: "bar" }
meta(a);
// { version: 2 }
const b = { ...a };
meta(b);
// undefined