Warum kann Array.prototype.forEach nicht verkettet werden?

9

Ich habe heute erfahren, dass forEach() undefined zurückgibt. Was für eine Verschwendung!

Wenn es das ursprüngliche Array zurückgibt, wäre es viel flexibler, ohne vorhandenen Code zu beschädigen. Gibt es einen Grund% forEach gibt undefined zurück.

Gibt es eine Möglichkeit, forEach mit anderen Methoden wie map & amp; filter ?

Zum Beispiel:

%Vor%

Würde nicht funktionieren, weil forEach nicht nett sein möchte und Sie alle Methoden vor forEach erneut ausführen müssen, um das Objekt in den Zustand zu bringen, der für forEach benötigt wird.

    
Jonathan Dumaine 24.03.2015, 08:37
quelle

1 Antwort

16

Was Sie wollen, ist bekannt als Methode Cascading über Methodenverkettung . Beschreiben Sie sie kurz:

  1. Die Verkettung von Methoden erfolgt, wenn eine Methode ein Objekt zurückgibt, das eine andere sofort aufgerufene Methode enthält. Zum Beispiel mit jQuery:

    %Vor%
  2. Die Kaskadierung von Methoden erfolgt, wenn mehrere Methoden für dasselbe Objekt aufgerufen werden. In einigen Sprachen können Sie beispielsweise Folgendes tun:

    %Vor%

    Was in JavaScript dem folgenden entspricht:

    %Vor%

JavaScript hat keine spezielle Syntax für die Methoden-Kaskadierung. Sie können jedoch die Methoden-Kaskadierung mit Methodenverkettung simulieren, wenn der erste Methodenaufruf this zurückgibt. Im folgenden Beispielcode, wenn bar this (d. H.% Co_de%) zurückgibt, entspricht die Verkettung der kaskadierenden Ausführung:

%Vor%

Einige Methoden wie foo und filter sind zwar verkettbar, aber nicht kaskadierbar, weil sie ein neues Array, aber nicht das ursprüngliche Array zurückgeben.

Andererseits ist die Funktion map nicht verkettbar, weil sie kein neues Objekt zurückgibt. Nun stellt sich die Frage, ob forEach kaskadierbar sein soll oder nicht.

Derzeit ist forEach nicht kaskadierbar. Dies ist jedoch kein wirkliches Problem, da Sie das Ergebnis des Zwischenarrays einfach in einer Variablen speichern und später verwenden können:

%Vor%

Ja, diese Lösung sieht hässlicher aus als die gewünschte Lösung. Allerdings mag ich es aus mehreren Gründen mehr als deinen Code:

  1. Dies ist konsistent, weil verkettbare Methoden nicht mit kaskadierbaren Methoden kombiniert werden. Daher fördert es einen funktionalen Stil der Programmierung (d. H. Programmierung ohne Nebenwirkungen).

    Kaskadierung ist inhärent eine effektive Operation, weil Sie eine Methode aufrufen und das Ergebnis ignorieren. Daher rufen Sie die Operation für ihre Nebenwirkungen und nicht für ihr Ergebnis auf.

    Andererseits haben verkettbare Funktionen wie forEach und map keine Nebenwirkungen (wenn ihre Eingabefunktion keine Nebenwirkungen hat). Sie werden nur für ihre Ergebnisse verwendet.

    Nach meiner bescheidenen Meinung ist das Mischen von verkettungsfähigen Methoden wie filter und map mit kaskadierbaren Funktionen wie filter (wenn es kaskadierbar wäre) ein Sakrileg, weil es in einer ansonsten reinen Transformation zu Nebenwirkungen führen würde.

  2. Es ist explizit. Als Das Zen von Python lehrt uns: "Explizit ist besser als implizit." Methodenkaskaden sind nur syntaktisch Zucker. Es ist implizit und es hat seinen Preis. Die Kosten sind Komplexität.

    Nun könnten Sie argumentieren, dass mein Code komplexer aussieht als Ihres. Wenn ja, würdest du das Buch nach seinem Cover beurteilen. In ihrer berühmten Veröffentlichung Aus der Teergrube beschreiben die Autoren Ben Moseley und Peter Marks verschiedene Arten von Softwarekomplexitäten.

    Die zweitgrößte Softwarekomplexität auf ihrer Liste ist die Komplexität, die durch explizite Beachtung des Kontrollflusses verursacht wird. Zum Beispiel:

    %Vor%

    Das obige Programm befasst sich explizit mit dem Kontrollfluss, weil Sie explizit angeben, dass forEach vor .forEach(passToAnotherObject) vorkommen sollte, obwohl dies keine Auswirkung auf die gesamte Transformation haben sollte.

    Tatsächlich können Sie es aus der Gleichung entfernen und es würde keinen Unterschied machen:

    %Vor%

    Dies deutet darauf hin, dass die .map(transformKeys) überhaupt keine Geschäfte in der Gleichung hatte. Da es eine Nebenwirkung ist, sollte es getrennt von reinem Code gehalten werden.

    Wenn Sie es explizit wie oben beschrieben schreiben, trennen Sie nicht nur reinen Code von nebenwirkendem Code, sondern Sie können auch auswählen, wann jede Berechnung ausgewertet werden soll. Zum Beispiel:

    %Vor%

    Ja, Sie befassen sich immer noch explizit mit dem Kontrollfluss. Jetzt wissen Sie zumindest, dass .forEach(passToAnotherObject) nichts mit den anderen Transformationen zu tun hat.

    Damit haben Sie einige (aber nicht alle) der Komplexität eliminiert, die durch die explizite Behandlung des Kontrollflusses verursacht wurde.

Aus diesen Gründen glaube ich, dass die aktuelle Implementierung von .forEach(passToAnotherObject) tatsächlich von Vorteil ist, weil Sie dadurch daran gehindert wird, Code zu schreiben, der aufgrund expliziter Beachtung des Kontrollflusses Komplexität einführt.

Ich weiß aus eigener Erfahrung, als ich bei BrowserStack gearbeitet habe, dass die explizite Behandlung des Kontrollflusses ein großes Problem im Groß- Softwareanwendungen skalieren. Es ist in der Tat ein Problem der realen Welt.

Es ist einfach, komplexen Code zu schreiben, weil komplexer Code normalerweise kürzerer (impliziter) Code ist. Es ist also immer verlockend, eine Nebenfunktion wie forEach mitten in einer reinen Berechnung einzutragen, weil es weniger Code-Refactoring benötigt.

Aber auf lange Sicht macht es Ihr Programm komplexer.Denken Sie darüber nach, was in ein paar Jahren passieren würde, wenn Sie das Unternehmen verlassen, für das Sie arbeiten, und jemand anderes Ihren Code pflegen muss. Ihr Code sieht jetzt so aus:

%Vor%

Die Person, die Ihren Code liest, muss jetzt davon ausgehen, dass alle zusätzlichen forEach -Methoden in Ihrer Kette essentiell sind, zusätzliche Arbeit leisten, um zu verstehen, was jede Funktion macht, selbst herausfinden, dass diese zusätzlichen forEach -Methoden nicht sind Wesentlich, um forEach zu berechnen, eliminiere sie aus ihrem mentalen Modell deines Codes und konzentriere dich nur auf die wesentlichen Teile.

Das ist eine Menge unnötiger Komplexität, die zu Ihrem Programm hinzugefügt wurde, und Sie dachten, dass es Ihr Programm einfacher macht.

    
Aadit M Shah 24.03.2015 10:32
quelle