Articles

WeakMaps (`WeakMap`) (haladó) – JavaScript türelmetlen programozóknak (ES2021 kiadás)

(Hirdetés, kérjük, ne blokkolja.)

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.

Következő: 35 készlet (Set)