JavaScript WeakMap und WeakSet

Im Kapitel Müllsammlung wurde festgestellt, dass die JavaScript-Engine einen Wert im Speicher halten kann, sobald er erreichbar ist.

Hier ist ein Beispiel:

Javascript remove object from memory
let js = { name: "Javascript" }; // object can be accessed, js is the reference to it // rewrite the reference js = null; // the object will be deleted from memory console.log(js);

In der Regel sind Eigenschaften oder Elemente von Datenstrukturen wie einem Objekt oder einem Array erreichbar und werden im Speicher gehalten, sobald diese Datenstruktur im Speicher ist. Zum Beispiel, nachdem man ein Objekt in ein Array gelegt hat, existiert es so lange wie das Array existiert.

Hier ist ein Beispiel:

Javascript cache a function result
let js = { name: "Javascript" }; let array = [js]; js = null; // rewrite the reference // js is stored in an array, so it will not garbage-collected // it can be received as an array[0] console.log(js);

Entsprechend, wenn man ein Objekt wie den Schlüssel in einer normalen Map verwendet, existiert es so lange, wie die Map existiert.

Ein Beispiel sieht wie folgt aus:

Javascript cache a function result
let js = { name: "Javascript" }; let map = new Map(); map.set(js, "..."); js = null; // rewriting the reference // js is on the map, // it can be received by using map.keys() console.log(js);

Des Weiteren werden wir WeakMap behandeln, die völlig anders ist und die Müllsammlung von Schlüsselobjekten nicht einschränkt.

WeakMap

Der Hauptunterschied zwischen Map und WeakMap ist, dass der WeakMap-Schlüssel keine primitiven Werte sein können. Sie müssen Objekte sein, wie im folgenden Beispiel:

Javascript WeakMap
let weakMap = new WeakMap(); let obj = {}; key1 = weakMap.set(obj, "ok"); // works fine, object key console.log(key1); // can't use string as key key2 = weakMap.set("test", "Oops"); // Error because the “test” is not an object console.log(key2);

Iteration und keys(), values(), entries()-Methoden werden von WeakMap nicht unterstützt.

Die von WeakMap unterstützten Methoden sind folgende: weakMap.get(key), weakMap.set(key, value), weakMap.has(key) und weakMap.delete(key).

weakMap.delete(key)

Zusätzlicher Datenspeicher ist das primäre Anwendungsgebiet für WeakMap. WeakMap ist besonders nützlich für das Speichern von Daten, die mit einer Drittanbieter-Bibliothek verbunden sind. Zum Beispiel, nehmen Sie in Betracht, die Daten in eine WeakMap zu legen, mit einem Objekt als Schlüssel. Sobald das Objekt gesammelt wird, werden auch die Daten automatisch gelöscht, wie unten gezeigt:

let weakMap = new WeakMap();
let obj = {
  name: "test"
};
key = weakMap.set(obj, "test docs");
// if obj disappears, test docs will be automatically destroyed

Nehmen Sie nun an, Sie haben einen Code, der einen Besuchszähler für die Benutzer führt. Die Informationen werden in einer Karte gespeichert, mit einem Benutzerobjekt als Schlüssel und der Besucherzahl als Wert.

Nachdem ein Benutzer gegangen ist, möchten Sie aufhören, deren Besuchszahl zu speichern.

Zuerst, sehen wir uns ein Beispiel einer Zählfunktion mit Map an. Sie sieht folgendermaßen aus:

Javascript WeakMap additional data
// visitsCount.js let visitsCountMap = new Map(); // map: book => visits count // increase the visits count function countBook(book) { let count = visitsCountMap.get(book) || 0; visitsCountMap.set(book, count + 1); console.log(count); } // main.js let js = { name: "Javascript" }; countBook(js); // count his visits countBook(js); // count his visits // later js leaves us js = null; console.log(js);

So, beim Entfernen der Benutzer ist es nötig, visitsCountMap zu säubern. Andernfalls wird es auf unbestimmte Zeit im Speicher gespeichert.

Allerdings kann sich das Säubern zu einer lästigen Aufgabe entwickeln. Wenn Sie dies vermeiden möchten, können Sie WeakMap verwenden. Hier ist ein Beispiel für die Verwendung von WeakMap anstelle dieser Art von Säuberung:

Javascript WeakMap additional data
// visitsCount.js let visitsCountMap = new WeakMap(); // weakmap: book => visits count // increase the visits count function countBook(book) { let count = visitsCountMap.get(book) || 0; visitsCountMap.set(book, count + 1); console.log(count); } // main.js let js = { name: "Javascript" }; countBook(js); // count his visits countBook(js); // count his visits // later js leaves us js = null; console.log(js);

Nun ist es nicht mehr notwendig, visitsCountMap zu säubern.

Über das Caching

Caching findet statt, wenn ein Funktionsergebnis gespeichert (gecached) werden muss, um es später bei einem Aufruf am gleichen Objekt wiederzuverwenden.

Map kann für die Speicherung von Ergebnissen wie folgt verwendet werden:

Javascript cache a function result
// cache.js let cache = new Map(); // calculate and remember the result function process(myObj) { if (!cache.has(myObj)) { let res = /* result calculations for */ myObj; cache.set(myObj, res); } return cache.get(myObj); } // Now we use process() in another file: // main.js let myObj = { /* let's say we have an object */ }; let res1 = process(myObj); // calculated // later from another place in the code let res2 = process(myObj); // the result taken from the cache is remembered // later when an object is no longer needed: myObj = null; console.log(cache.size); // 1

Im Falle des Aufrufs von process(obj) mit demselben Objekt mehrere Male, wird das Ergebnis nur das erste Mal berechnet. Danach wird die Information aus dem Cache genommen.

Der einzige Nachteil des Caching ist, dass Sie den Cache säubern müssen, sobald Sie das Objekt nicht mehr benötigen.

Das Ersetzen von Map durch WeakMap wird das Problem lösen. Die gecachte Information wird automatisch aus dem Speicher gelöscht, sobald das Objekt gesammelt wurde.

Um genauer zu sein, betrachten wir das folgende Beispiel:

// cache.js
let cache = new WeakMap();
// calculate and remember the result
function process(obj) {
  if (!cache.has(obj)) {
    let res = /* calculate the result for */ obj;
    cache.set(obj, res);
  }
  return cache.get(obj);
}
 
// main.js
let obj = { /* some object */ };
let res1 = process(obj);
let res2 = process(obj);
// later, when object is no longer needed:
obj = null;
// Can not get cache.size because it is  WeakMap,
// but it is 0 or soon will be 0
//Once object gets garbage collected, the cached data will also be cleaned

WeakSet

WeakSet wird als äquivalent zu Set betrachtet. Aber nur Objekte und keine primitives können zu WeakSet hinzugefügt werden.

Ein Objekt befindet sich in dem Set, solange es an anderer Stelle erreichbar ist.

WeakSet unterstützt auch has, add und delete. Aber keine Iterationen oder size und keys()sind unterstützt.

Auch kann es als zusätzlicher Speicher für Daten dienen, aber nicht für beliebige Daten. Hier ist ein Beispiel für das Hinzufügen von Sprachen zu WeakSet um den Überblick über diejenigen, die die Seite erstellt haben, zu behalten:

Javascript WeakSet
let createdSet = new WeakSet(); let html = { name: "Html" }; let php = { name: "php" }; let js = { name: "Javascript" }; createdSet.add(html); // Html created us createdSet.add(js); // Then Javascript createdSet.add(html); // Html again // createdSet has 2 languages now // check if html created? console.log(createdSet.has(html)); // true // check if php created? console.log(createdSet.has(php)); // false html = null; // createdSet will be cleaned automatically

Es gibt eine bedeutende Einschränkung in WeakMap und WeakSet: es gibt keine Iterationen. Auch besteht keine Möglichkeit, den aktuellen Inhalt zu erhalten.

Zusammenfassung

In diesem Kapitel haben wir WeakMap und WeakSet behandelt.

Zusammenfassend kann man sagen, dass WeakMap als eine Map-ähnliche Sammlung betrachtet wird, die nur Objekte als Schlüssel zulässt. Sie löscht diese zusammen mit dem zugehörigen Wert, wenn sie nicht mehr erreichbar sind.

WeakSet wird als eine Set-ähnliche Sammlung betrachtet, die nur Objekte speichert und diese löscht, wenn sie nicht mehr erreichbar werden.

Beide Kollektionen unterstützen keine Eigenschaften und Methoden, die sich nicht auf alle Schlüssel oder ihre Anzahl beziehen. Sie erlauben nur individuelle Operationen.

Quizzeit: Testen Sie Ihre Fähigkeiten!

Sind Sie bereit, das Gelernte herauszufordern? Tauchen Sie ein in unsere interaktiven Quizze für ein tieferes Verständnis und eine unterhaltsame Art, Ihr Wissen zu festigen.

Finden Sie das nützlich?