Signatur
Beschreibung
Das Set-Objekt ermöglicht es, eindeutige Werte beliebigen Typs zu speichern, sei es primitive Werte oder Objektreferenzen.
Set-Objekte sind Sammlungen von Werten. Ein Wert im Set darf nur einmal vorkommen; er ist innerhalb der Sammlung des Sets eindeutig. Die Elemente eines Sets können in Einfügereihenfolge iteriert werden. Die Einfügereihenfolge entspricht der Reihenfolge, in der jedes Element durch die Methode add() erfolgreich in das Set eingefügt wurde (das heißt, es war kein identisches Element bereits im Set, als add() aufgerufen wurde).
Die Spezifikation verlangt, dass Sets so implementiert werden, „dass sie im Durchschnitt Zugriffszeiten bieten, die sublinear zur Anzahl der Elemente in der Sammlung sind". Daher könnte es intern als Hashtabelle (mit O(1)-Lookup), als Suchbaum (mit O(log(N))-Lookup) oder als jede andere Datenstruktur dargestellt werden, solange die Komplexität besser als O(N) ist.
Wertegleichheit
Die Wertegleichheit basiert auf dem SameValueZero-Algorithmus. (Früher wurde SameValue verwendet, das 0 und -0 als unterschiedlich behandelte. Siehe Browser-Kompatibilität.) Das bedeutet, dass NaN als gleich mit NaN betrachtet wird (obwohl NaN !== NaN), und alle anderen Werte werden gemäß der Semantik des ===-Operators als gleich angesehen. Auch bei Objektschlüsseln basiert die Gleichheit auf der Objektidentität. Sie werden per Referenz und nicht per Wert verglichen.
Performance
Die has-Methode prüft, ob ein Wert im Set enthalten ist, und verwendet dabei einen Ansatz, der im Durchschnitt schneller ist als das Testen der meisten zuvor hinzugefügten Elemente. Insbesondere ist sie im Durchschnitt schneller als die Methode Array.prototype.includes, wenn ein Array eine length hat, die der size eines Sets entspricht.
Set-Komposition
Das Set-Objekt bietet einige Methoden, mit denen sich Sets wie bei mathematischen Operationen kombinieren lassen. Zu diesen Methoden gehören: A.difference(B), A.intersection(B), A.symmetricDifference(B), A.union(B), A.isDisjointFrom(B), A.isSubsetOf(B) und A.isSupersetOf(B).
Um sie allgemeiner nutzbar zu machen, akzeptieren diese Methoden nicht nur Set-Objekte, sondern alles, was set-like ist.
Set-like Objekte
Alle Set-Kompositionsmethoden erfordern, dass this eine tatsächliche Set-Instanz ist, aber ihre Argumente müssen nur set-like sein. Ein set-like Objekt ist ein Objekt, das Folgendes bereitstellt:
- Eine
size-Eigenschaft, die eine Zahl enthält. - Eine
has()-Methode, die ein Element entgegennimmt und einen boolean zurückgibt. - Eine
keys()-Methode, die einen iterator der Elemente im Set zurückgibt.
Zum Beispiel sind Map-Objekte set-like, weil sie ebenfalls size, has() und keys() besitzen und sich daher wie Sets von Schlüsseln verhalten, wenn sie in Set-Methoden verwendet werden.
Arrays sind nicht set-like, weil sie weder eine has()-Methode noch die size-Eigenschaft besitzen, und ihre keys()-Methode Indizes anstelle von Elementen liefert. Auch WeakSet-Objekte sind nicht set-like, weil sie keine keys()-Methode haben.
Set-like Browser-APIs
Browser-Set-like-Objekte (oder „setlike objects") sind Web-API-Schnittstellen, die sich in vielerlei Hinsicht wie ein Set verhalten.
Genau wie bei Set können die Elemente in der gleichen Reihenfolge iteriert werden, in der sie dem Objekt hinzugefügt wurden. Set-like-Objekte und Set haben außerdem Eigenschaften und Methoden mit gleichem Namen und Verhalten. Im Gegensatz zu Set erlauben sie jedoch nur einen bestimmten vordefinierten Typ für jeden Eintrag.
Die erlaubten Typen werden in der IDL-Definition der Spezifikation festgelegt. Zum Beispiel ist GPUSupportedFeatures ein Set-like-Objekt, das Strings als Schlüssel/Wert verwenden muss.
Set-like-Objekte sind entweder schreibgeschützt oder les- und schreibbar (siehe das Schlüsselwort readonly in der IDL).
- Schreibgeschützte
Set-like-Objekte besitzen die Eigenschaftsizesowie die Methodenentries(),forEach(),has(),keys(),values()und[Symbol.iterator](). - Beschreibbare
Set-like-Objekte besitzen zusätzlich die Methodenclear(),delete()undadd().
Die Methoden und Eigenschaften verhalten sich genauso wie die entsprechenden Entitäten in Set, abgesehen von der Einschränkung der Eintragstypen.
Beispiele für schreibgeschützte Set-like-Browserobjekte sind GPUSupportedFeatures und XRAnchorSet. Beispiele für beschreibbare Set-like-Browserobjekte sind CustomStateSet, FontFaceSet, Highlight und ViewTransitionTypeSet.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $iterable | Iterable<T> | null | undefined | undefined | Ein optionales iterierbares Objekt (z. B. ein Array), dessen Werte als Anfangselemente in das Set eingefügt werden. Duplikate werden dabei direkt verworfen. |
Rückgabewert
Set-Instanz, die die angegebenen eindeutigen Werte enthält.Beispiele
Verwendung des Set-Objekts
const mySet1 = new Set();
mySet1.add(1); // Set(1) { 1 }
mySet1.add(5); // Set(2) { 1, 5 }
mySet1.add(5); // Set(2) { 1, 5 }
mySet1.add("some text"); // Set(3) { 1, 5, 'some text' }
const o = { a: 1, b: 2 };
mySet1.add(o);
mySet1.add({ a: 1, b: 2 }); // o is referencing a different object, so this is okay
mySet1.has(1); // true
mySet1.has(3); // false, since 3 has not been added to the set
mySet1.has(5); // true
mySet1.has(Math.sqrt(25)); // true
mySet1.has("Some Text".toLowerCase()); // true
mySet1.has(o); // true
mySet1.size; // 5
mySet1.delete(5); // removes 5 from the set
mySet1.has(5); // false, 5 has been removed
mySet1.size; // 4, since we just removed one value
mySet1.add(5); // Set(5) { 1, 'some text', {...}, {...}, 5 } - a previously deleted item will be added as a new item, it will not retain its original position before deletion
console.log(mySet1); // Set(5) { 1, "some text", {…}, {…}, 5 }
Iterieren über Sets
for (const item of mySet1) {
console.log(item);
}
// 1, "some text", { "a": 1, "b": 2 }, { "a": 1, "b": 2 }, 5
for (const item of mySet1.keys()) {
console.log(item);
}
// 1, "some text", { "a": 1, "b": 2 }, { "a": 1, "b": 2 }, 5
for (const item of mySet1.values()) {
console.log(item);
}
// 1, "some text", { "a": 1, "b": 2 }, { "a": 1, "b": 2 }, 5
// key and value are the same here
for (const [key, value] of mySet1.entries()) {
console.log(key);
}
// 1, "some text", { "a": 1, "b": 2 }, { "a": 1, "b": 2 }, 5
// Convert Set object to an Array object, with Array.from
const myArr = Array.from(mySet1); // [1, "some text", {"a": 1, "b": 2}, {"a": 1, "b": 2}, 5]
// the following will also work if run in an HTML document
mySet1.add(document.body);
mySet1.has(document.querySelector("body")); // true
// converting between Set and Array
const mySet2 = new Set([1, 2, 3, 4]);
console.log(mySet2.size); // 4
console.log([...mySet2]); // [1, 2, 3, 4]
// intersect can be simulated via
const intersection = new Set([...mySet1].filter((x) => mySet2.has(x)));
// difference can be simulated via
const difference = new Set([...mySet1].filter((x) => !mySet2.has(x)));
// Iterate set entries with forEach()
mySet2.forEach((value) => {
console.log(value);
});
// 1
// 2
// 3
// 4
Implementierung grundlegender Set-Operationen
function isSuperset(set, subset) {
for (const elem of subset) {
if (!set.has(elem)) {
return false;
}
}
return true;
}
function union(setA, setB) {
const _union = new Set(setA);
for (const elem of setB) {
_union.add(elem);
}
return _union;
}
function intersection(setA, setB) {
const _intersection = new Set();
for (const elem of setB) {
if (setA.has(elem)) {
_intersection.add(elem);
}
}
return _intersection;
}
function symmetricDifference(setA, setB) {
const _difference = new Set(setA);
for (const elem of setB) {
if (_difference.has(elem)) {
_difference.delete(elem);
} else {
_difference.add(elem);
}
}
return _difference;
}
function difference(setA, setB) {
const _difference = new Set(setA);
for (const elem of setB) {
_difference.delete(elem);
}
return _difference;
}
// Examples
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([2, 3]);
const setC = new Set([3, 4, 5, 6]);
isSuperset(setA, setB); // returns true
union(setA, setC); // returns Set {1, 2, 3, 4, 5, 6}
intersection(setA, setC); // returns Set {3, 4}
symmetricDifference(setA, setC); // returns Set {1, 2, 5, 6}
difference(setA, setC); // returns Set {1, 2}
Beziehung zu Arrays
const myArray = ["value1", "value2", "value3"];
// Use the regular Set constructor to transform an Array into a Set
const mySet = new Set(myArray);
mySet.has("value1"); // returns true
// Use the spread syntax to transform a set into an Array.
console.log([...mySet]); // Will show you exactly the same Array as myArray
Doppelte Elemente aus einem Array entfernen
// Use to remove duplicate elements from an array
const numbers = [2, 13, 4, 4, 2, 13, 13, 4, 4, 5, 5, 6, 6, 7, 5, 32, 13, 4, 5];
console.log([...new Set(numbers)]); // [2, 13, 4, 5, 6, 7, 32]
Beziehung zu Strings
// Case sensitive (set will contain "F" and "f")
new Set("Firefox"); // Set(7) [ "F", "i", "r", "e", "f", "o", "x" ]
// Duplicate omission ("f" occurs twice in the string but set will contain only one)
new Set("firefox"); // Set(6) [ "f", "i", "r", "e", "o", "x" ]
Ein Set zur Sicherstellung der Eindeutigkeit einer Werteliste verwenden
const array = Array.from(document.querySelectorAll("[id]")).map((e) => e.id);
const set = new Set(array);
console.assert(set.size === array.length);
Map als set-like Objekt
const a = new Set([1, 2, 3]);
const b = new Map([
[1, "one"],
[2, "two"],
[4, "four"],
]);
console.log(a.union(b)); // Set(4) {1, 2, 3, 4}
// Wichtig · Fallstricke
keys() anstelle von [Symbol.iterator]() auf, um Elemente zu erzeugen. Dadurch werden Maps zu gültigen set-like Objekten, denn bei Maps liefert der iterator entries, während die has()-Methode keys entgegennimmt.