Pep: Frage zu Rückgabewerten von filter() bzw. find()

Hallo,

Okay, nicht wirklich eine Frage. ...eher eine Spielerei, quasi für hier anwesende Javascript Nerds wie mich :)

Es sei angemerkt, alles "funktioniert", folgendes also eine REINE Verständnisfrage:

Bin in meinem Code über die Situation gestolpert, dass ich aus einem Array "arr" mit Buchstaben von "a" bis "z" alle Konsonanten herausfiltern wollte. Dazu habe ich ein Array

const vowels = ["a", "e", "i", "o", "u"];

geschaffen und dann die Konsonanten wie folgt gefiltert:

// BEWEISSTÜCK 1
const consonants = arr.filter(cur => !vowels.find(el => el === cur));

Gleichsam ließen sich natürlich die Vokale filtern:


// BEWEISSTÜCK 2
const newVowels = arr.filter(cur => vowels.find(el => el === cur)); // "vowels" vs "newVowels" - SÄMTLICHE  Naming Conventions out the window :O

NUN ZUR EIGENTLICHEN FRAGE!:

WARUM funktioniert das eigentlich?

filter() siebt alle als "true" zurückgegebenen Werte aus. find() hingegen liefert ja NICHT explizit "true" oder "false", sondern den ersten gefundenen Wert, BZW.(!) "undefined", wenn kein Wert gefunden wurde. BEWEISSTÜCK 1 lässt sich daher übersetzen als

const consonants = arr.filter(cur => !undefined); // Konsonanten werden in vowels ja nicht gefunden!

"!undefined" === "true", daher soweit alles gut

BEWEISSTÜCK 2 aber gibt ja nicht explizit true zurück, sondern den ersten Wert, der ein Match ergibt, daher


const newVowels = arr.filter(cur => "a"); // bzw. "e", "i",... je nach Wert von "cur", hier ist "cur" "a"

Warum wird hier der zurückgegebene Vokal (in diesem Beispiel bei diesem Durchgang "a") als "true" von filter() interpretiert?

Wie beschrieben... Spielerei... trotzdem danke!

Pep

  1. Hallo Pep,

    Diese Frage stellte schon Pilatus...

    Was ist Wahrheit? - er hatte allerdings größere Probleme mit der Antwort als wir hier 😉.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Jetzt bin ich restlos verwirrt und stehe HEMMUNGSLOST auf der Leitung.

      console.log("a" == true);
      

      ergibt FALSE

      In vorigem Beispiel [BEWEISSTÜCK 2] ist "a" aber truthy

      const newVowels = arr.filter(cur => "a");
      

      Oder höflich ausgedrückt: HÄH?!

      1. Hi,

        console.log("a" == true);
        

        ergibt FALSE

        hier wird m.E. einer der beiden Operanden (vermutlich der zweite) typ-konvertiert, damit er zum anderen paßt (die genauen Regeln weiß ich nicht auswendig), und dann erst verglichen.

        In vorigem Beispiel [BEWEISSTÜCK 2] ist "a" aber truthy

        const newVowels = arr.filter(cur => "a");
        

        Hier wird direkt von "a" die truthiness ausgewertet.

        cu,
        Andreas a/k/a MudGuard

        1. Hallo MudGuard,

          Das sind die Feinheiten bei denen ich auch erstmal grübeln muss.

          Du dürftest aber recht haben, die type coercion müsste zum allgemeineren Typ hin verlaufen und deshalb "a"==true gleichbedeutend sein mit "a"=="true".

          Edit: Das war falsch und das Minus wohlverdient. Die Coercion liefert NaN == 1. Siehe den späteren Beitrag.

          Rolf

          --
          sumpsi - posui - obstruxi
          1. Hallo, okay, bin hier wohl auf des Pudels Kern gestoßen.

            == lässt wohl Vergleiche unabhängig des Typs zu, indem es eine Nicht-Nummer in eine Nummer umwandelt

            
            10 == '10' // ==>	10 == 10	// ==> TRUE
            true == 1 // ==>	1 == 1		// TRUE
            true == 'true' // ==> 	1 == NaN	// FALSE
            
            

            Hier muss es aber wohl eine andere Regel für Strings geben ....(?)

            1. Hallo,

              bin hier wohl auf des Pudels Kern gestoßen.

              == lässt wohl Vergleiche unabhängig des Typs zu, indem es eine Nicht-Nummer in eine Nummer umwandelt

              so lässt es der verlinkte Beitrag vermuten. Aber er unterschlägt ein wichtiges Detail.

              10 == '10' // ==>	10 == 10	// ==> TRUE
              true == 1 // ==>	1 == 1		// TRUE
              true == 'true' // ==> 	1 == NaN	// FALSE
              

              Hier muss es aber wohl eine andere Regel für Strings geben ....(?)

              Warum? Welche?

              Solange die beiden Operanden vom gleichen Typ sind, wird natürlich nichts konvertiert, sonst wäre ein Stringvergleich ja prinzipiell nicht möglich. Genau das erwähnt der Artikel nicht - vermutlich weil es selbstverständlich ist.

              Einen schönen Tag noch
               Martin

              --
              Wie man sich bettet, so schallt es heraus.
            2. Hallo Pep,

              wie ich schon schrieb, das sind Feinheiten die man nicht unbedingt im Kopf hat. Ich habe dazu nochmal recherchiert und update das Wiki dementsprechend (hier, ist aber noch nicht gespeichert).

              Der Fall "a" == true löst sich so auf:

              • Booleans werden vor einem == Test grundsätzlich in eine Zahl umgewandelt
                (true → 1, false → 0)

              "a" == 1

              • Der Vergleich eines Strings mit einer Zahl erfolgt so, dass der String in seinen numerischen Wert konvertiert wird
                "a"NaN

              NaN == 1
              false

              Man sagt oft, dass die beiden folgenden if gleichwertig sind:

              if (a) { ... }
              if (a == true) { ... }
              

              Nein, nicht in JavaScript. Der erste if-Block wird für jeden Wert ausführt, der truthy ist. Der zweite if-Block dagegen nur für diejenigen a, für die Number(a) die Zahl 1 ergibt.

              Gleichwertig sind dagegen diese Abfragen:

              if (a) { ... }
              if (!!a == true) { ... }
              if (!!a === true) { ... }
              if (Boolean(a) == true) { ... }
              if (Boolean(a) === true) { ... }
              

              Im Zeile 2 und 3 sorgt die doppelte Negation von a dafür, dass jedes a, das truthy ist, zu true wird.
              In Zeile 4 und 5 konvertiert die Boolean-Funktion jeden falsy-Wert zu false und den Rest zu true. Damit klappt es auch.
              Und weil mit !! bzw. Boolean dafür gesorgt wird, dass aus truthy true wird, ist es dann auch egal, ob man == oder === verwendet.

              Die entsprechenden PHP Regeln habe ich jetzt noch nicht studiert. Sie sind vermutlich in feinen, aber gemeinen Details anders.

              Und wie wird man das Problem gründlich los?

              Verwende nicht .find(), sondern .some() oder besser noch .includes(). Die liefern true oder false zurück und du hast die Frage nach der echten Wahrheit nicht mehr zu klären. Mit .includes hast Du noch den Vorteil, dass Du keine geschachtelte Callback-Funktion brauchst.

              Rolf

              --
              sumpsi - posui - obstruxi