Rolf B: Javascript includes einzelne Array Werte

Beitrag lesen

problematische Seite

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