Hallo ebody,
(1) Ein Konstrukt vom Typ if (something === true)
lässt sich als if (something)
verkürzen, wenn man weiß, dass something
definitiv ein boolescher Wert ist. Beim Ergebnis von includes ist das der Fall.
Eine Abfrage auf === true
brauchst Du nur, wenn Du außer true
auch truthy Werte (Siehe unser Wiki, "Was ist Wahrheit") bekommen könntest und diese nicht als true akzeptieren willst.
(2) Es gibt die so genannten Quantorfunktionen für Arrays, die ermitteln, ob ein Callback für mindestens ein Array-Element (some
) oder für alle Array-Elemente (every
) zutrifft. Die kannst Du statt der zusätzlichen Schleife nutzen, landest dann aber bei mehrfach geschachtelten Pfeilfunktionen. Für Mathematiker: some
entspricht $$\exists$$ und every
implementiert $$\forall$$.
(3) Ich würde Dir definitiv empfehlen, für den filter-Callback eine Funktion zu verwenden. Und zwar so, dass Du über eine Helfer-Funktion gehst, die die gesuchten Genres als Parameter erhält und eine Funktion zurückgibt, die als Callback genutzt wird. Die übergebenen Genres stehen dieser Callbackfunktion dann als Teil der gebildeten Closure zur Verfügung.
Was unklar ist: Machst Du eine "UND" oder eine "ODER" Suche? Wenn ich Dir [ "Komödie", "Horror" ] vorgebe - suchst Du dann alle Horrorkomödien oder alles, was Horror oder Komödie ist? Anders gefragt: Brauchst Du some
oder every
? Aber man kann ja zwei Callback-Generatoren bereitstellen:
function createFilterForAll(...genresToFind) {
// User hat Array übergeben - ... legt ein weiteres Array drumherum
if (Array.isArray(genresToFind[0]))
genresToFind = genresToFind[0];
return movie => genresToFind.every(genre => movie.genres.includes(genre));
}
function createFilterForSome(...genresToFind) {
// User hat Array übergeben - ... legt ein weiteres Array drumherum
if (Array.isArray(genresToFind[0]))
genresToFind = genresToFind[0];
return movie => genresToFind.some(genre => movie.genres.includes(genre));
}
movies.filter(createFilterForAll("Horror", "Komödie"));
movies.filter(createFilterForSome("Horror", "Komödie"));
Die isArray Abfrage ist drin, falls jemand filterForAll(["Horror", "Komödie"])
aufruft - in dem Fall macht der Rest-Parameter ...genresToFind
ein weiteres Array drumherum, das entfernt werden muss.
"every
" und "some
" kennt sogar schon der IE, aber Rest-Parameter nicht. Wenn Du auch im IE funktionieren willst, musst Du statt Rest-Parametern das arguments Objekt verwenden (was aber kein Array ist, d.h. Du musst every und some als Schleife ausprogrammieren) oder einfach definieren, dass der User ein Array übergeben muss. Letzteres macht auch die isArray Prüfung obsolet.
Einen solchen Filter kannst Du - wenn das not tut - auch vorab erzeugen und speichern.
Mich persönlich würde jetzt noch triggern, dass die beiden Funktionen sich lediglich darin unterscheiden, ob sie mit some
oder every
suchen, und ich würde das vermutlich noch abstrahieren. Und in ein Objekt kapseln. Das wird dann aber schwerer verständlich. Aussehen täte es so:
const createFilter = (function() {
function createFilter(genresToFind, quantor) {
// Durch ... kann ein Array of Array entstehen
if (Array.isArray(genresToFind[0]))
genresToFind = genresToFind[0];
return movie => quantor.call(
genresToFind,
movie => movie.genres.includes(genre));
}
return {
all(...genresToFind) {
return createFilter(genresToFind, Array.prototype.every);
},
some(...genresToFind) {
return createFilter(genresToFind, Array.prototype.some);
}
}
})();
movies.filter(createFilter.all("Horror", "Komödie"));
movies.filter(createFilter.some("Horror", "Komödie"));
Die Kurzschreibweise für Methoden in Objektliteralen kennt der IE nicht, dort bräuchtest Du
return {
all: function() {
return createFilter(arguments, Array.prototype.every);
},
some: function() {
return createFilter(arguments, Array.prototype.some);
}
Rolf
sumpsi - posui - obstruxi