WeakMaps (`WeakMap`) (haladó) – JavaScript türelmetlen programozóknak (ES2021 kiadás)
34 WeakMaps (WeakMap) (haladó)
- 34.1 WeakMapok fekete dobozok
- 34.2 A WeakMap kulcsai gyengén vannak tartva
- 34.2.1 Minden WeakMap kulcsnak objektumnak kell lennie
- 34.2.2 Felhasználási eset: értékek csatolása objektumokhoz
- 34.3 Példák
- 34.3.1 Számított eredmények gyorsítótárazása WeakMaps segítségével
- 34.3.2 Privát adatok tárolása WeakMapsben
- 34.4 WeakMap API
A WeakMap-ek hasonlóak a Maps-ekhez, a következő különbségekkel:
- Fekete dobozok, ahol egy értékhez csak akkor lehet hozzáférni, ha a WeakMap és a kulcs is a birtokunkban van.
- A WeakMap kulcsait gyengén tartják: ha egy objektum kulcs egy WeakMap-ben, akkor is lehet szemétbe gyűjteni. Ez lehetővé teszi számunkra, hogy a WeakMap-eket arra használjuk, hogy adatokat csatoljunk objektumokhoz.
A következő két szakaszban részletesebben megvizsgáljuk, hogy ez mit jelent.
34.1 A WeakMap-ek fekete dobozok
A WeakMap-ek belsejét nem lehet megvizsgálni:
- nem lehet például iterálni vagy loopolni a kulcsokon, értékeken vagy bejegyzéseken. És nem lehet kiszámítani a méretet sem.
- Egy WeakMapot ráadásul törölni sem lehet – egy új példányt kell létrehozni.
Ezek a korlátozások egy biztonsági tulajdonságot tesznek lehetővé. Mark Miller idézve:
A weakmap/kulcspár értékének leképezését csak az figyelheti meg vagy befolyásolhatja, aki rendelkezik a weakmap és a kulcs értékével is. A
clear()
esetén valaki, akinek csak a WeakMap van a birtokában, képes lett volna befolyásolni a WeakMap és a kulcs-érték leképezést.
34.2 A WeakMap kulcsai gyengén birtokoltak
A WeakMap kulcsairól azt mondjuk, hogy gyengén birtokoltak: Normális esetben, ha egy objektum egy másikra hivatkozik, akkor az utóbbi objektumot nem lehet szemétbe gyűjteni, amíg az előbbi létezik. Egy WeakMap esetében ez másképp van: ha egy objektum kulcs, és nem hivatkozik másra, akkor addig lehet kukázni, amíg a WeakMap létezik. Ez a megfelelő bejegyzés eltávolításához is vezet (de ezt nem lehet megfigyelni).
34.2.1 Minden WeakMap kulcsnak objektumnak kell lennie
Minden WeakMap kulcsnak objektumnak kell lennie. Hibát kapsz, ha primitív értéket használsz:
> const wm = new WeakMap();> wm.set(123, 'test')TypeError: Invalid value used as weak map key
A primitív értékek kulcsként való használatával a WeakMapek már nem lennének fekete dobozok. De mivel a primitív értékek sosem kerülnek szemétbe, a gyengén tartott kulcsokból amúgy sem profitálunk, és ugyanúgy használhatunk egy normál Mapet.
34.2.2 Felhasználási eset: értékek objektumokhoz csatolása
Ez a WeakMaps fő felhasználási esete: arra használhatjuk őket, hogy külsőleg értékeket csatoljunk objektumokhoz – például:
const wm = new WeakMap();{ const obj = {}; wm.set(obj, 'attachedValue'); // (A)}// (B)
Az A sorban a obj
-hez csatolunk egy értéket. A B sorban obj
már szemétbe kerülhet, annak ellenére, hogy wm
még mindig létezik. Ez a technika, hogy egy objektumhoz értéket csatolunk, egyenértékű azzal, hogy az objektum egy tulajdonságát kívülről tároljuk. Ha wm
egy tulajdonság lenne, az előző kód így nézne ki:
{ const obj = {}; obj.wm = 'attachedValue';}
34.3 Példák
34.3.1 A kiszámított eredmények tárolása WeakMaps segítségével
A WeakMaps segítségével korábban kiszámított eredményeket társíthatunk objektumokhoz anélkül, hogy a memóriakezeléssel kellene foglalkoznunk. A következő countOwnKeys()
függvény egy példa: a korábbi eredményeket a WeakMap cache
-ban gyorsítótárazza.
const cache = new WeakMap();function countOwnKeys(obj) { if (cache.has(obj)) { return ; } else { const count = Object.keys(obj).length; cache.set(obj, count); return ; }}
Ha ezt a függvényt egy obj
objektummal használjuk, láthatjuk, hogy az eredményt csak az első hívásnál számítjuk ki, míg a második hívásnál egy gyorsítótárazott értéket használunk:
> const obj = { foo: 1, bar: 2};> countOwnKeys(obj)> countOwnKeys(obj)
34.3.2 Privát adatok tárolása WeakMaps
A következő kódban a _counter
és _action
WeakMaps _counter
és _action
a Countdown
példányok virtuális tulajdonságainak értékeinek tárolására szolgál:
const _counter = new WeakMap();const _action = new WeakMap();class Countdown { constructor(counter, action) { _counter.set(this, counter); _action.set(this, action); } dec() { let counter = _counter.get(this); counter--; _counter.set(this, counter); if (counter === 0) { _action.get(this)(); } }}// The two pseudo-properties are truly private:assert.deepEqual( Object.keys(new Countdown()), );
Így használjuk a Countdown
-t:
let invoked = false;const cd = new Countdown(3, () => invoked = true);cd.dec(); assert.equal(invoked, false);cd.dec(); assert.equal(invoked, false);cd.dec(); assert.equal(invoked, true);
Gyakorlat: GyengeMaps a privát adatokhoz
exercises/weakmaps/weakmaps_private_data_test.mjs
34.4 WeakMap API
A WeakMap
konstruktora és négy metódusa ugyanúgy működik, mint a Map
megfelelőik:
-
new WeakMap<K, V>(entries?: Iterable<>)
-
.delete(key: K) : boolean
-
.get(key: K) : V
-
.has(key: K) : boolean
-
.set(key: K, value: V) : this
Kvíz
Lásd: kvíz alkalmazás.
Set
)