Ein Tutorial (für Javascript) schlägt vor, dass wir eine Funktion wie diese schreiben:
function sayHello() {
//Some comments explaining the next line
window.alert("Hello");
}
Abgesehen von der Verschleierung hat das Schreiben im wirklichen Leben Vorteile? Wenn ja, welche Vorteile ergeben sich daraus?
language-agnostic
functions
Daniel
quelle
quelle
Antworten:
Bitte entschuldigen Sie mein Gedächtnis, wenn ich diese falsche ... Javascript ist nicht meine bevorzugte Implementierungssprache.
Es gibt mehrere Gründe, warum man möchte, dass eine No-Arg-Funktion einen anderen Funktionsaufruf umschließt. Während der einfache Anruf
window.alert("Hello");
etwas ist, das Sie sich vorstellen können, anstatt direkt anzurufensayHello()
.Aber was ist, wenn mehr dahinter steckt? Sie haben ein Dutzend Orte, an denen Sie anrufen möchten,
sayHello()
und habenwindow.alert("Hello");
stattdessen geschrieben . Jetzt möchten Sie, dass es awindow.alert("Hello, it is now " + new Date())
. Wenn Sie alle diese Anrufe umbrochen haben, währendsayHello()
Sie sie an einer Stelle ändern. Wenn nicht, ändern Sie es an ein Dutzend Stellen. Dies berührt Don't Repeat Yourself . Sie tun es, weil Sie es in Zukunft nicht ein Dutzend Mal tun müssen möchten.Ich habe in der Vergangenheit mit einer i18n / l10n- Bibliothek gearbeitet, die Funktionen zur clientseitigen Lokalisierung des Texts verwendete. Betrachten Sie die
sayHello()
Funktion. Sie können es ausdrucken lassen,hola
wenn der Benutzer in eine spanische Sprache lokalisiert ist. Das könnte ungefähr so aussehen:Allerdings hat die Bibliothek nicht so funktioniert. Stattdessen hatte es eine Reihe von Dateien, die so aussahen:
Anschließend erkennt die Bibliothek die Spracheinstellung des Browsers und erstellt dynamische Funktionen mit der entsprechenden Lokalisierung als Rückgabewert für einen nicht berechtigten Funktionsaufruf basierend auf der entsprechenden Lokalisierungsdatei.
Ich bin nicht genug von einem Javascript-Programmierer, um zu sagen, ob das gut oder schlecht ist ... nur, dass es ein möglicher Ansatz war und sein kann.
Der Punkt ist, den Aufruf einer anderen Funktion in eine eigene Funktion zu verpacken. Dies ist oft sehr nützlich und hilft bei der Modularisierung der Anwendung. Außerdem kann dies zu einer besseren Lesbarkeit des Codes führen.
Abgesehen davon arbeiten Sie an einem Tutorial. Am Anfang gilt es, die Dinge so einfach wie möglich vorzustellen. Die Einführung von Funktionsaufrufen im varargs-Stil von Anfang an kann für eine Person, die mit der Codierung im Allgemeinen nicht vertraut ist, zu sehr verwirrendem Code führen. Es ist viel einfacher, von keinen Argumenten zu Argumenten und zu Varagrammen zu wechseln - mit jedem Aufbau auf den vorherigen Beispielen und dem Verständnis.
quelle
window.alert
wird auch oft als Platzhalter während der Entwicklung verwendet, bis ein nettes Modal / Popup entworfen / implementiert werden kann, so dass es, genau wie das Sprachproblem, viel einfacher ausgetauscht werden kann. Wenn Sie bereits eine haben, sind für ein Design-Update einige Jahre später möglicherweise ähnliche Änderungen erforderlich.Ich denke, es ist manchmal nützlich, um die Implementierung zu verbergen.
Und das gibt Ihnen die Flexibilität, es später zu ändern
quelle
Zentralisierung: Obwohl die Implementierung nur eine Zeile lang ist, ziehen Sie es wahrscheinlich vor, diese Zeile an einer einzigen Stelle zu ändern, wenn sich diese häufig ändert, als überall dort, wo sayHello aufgerufen wird.
Minimieren / Ausblenden von Abhängigkeiten: Ihr Client-Code muss nicht mehr wissen, dass es ein Fensterobjekt gibt, und Sie können sogar die gesamte Implementierung ändern, ohne den Client-Code zu beeinflussen
Vertragserfüllung: Client-Code kann ein Modul erwarten, das eine sayHello-Funktion hat. In diesem Fall muss die Funktion vorhanden sein, auch wenn sie trivial ist.
Konsistenz von Abstraktionsebenen: Wenn Client-Code Operationen auf hoher Ebene verwendet, liegt es in Ihrem Interesse, Client-Code in Form von "sayHello", "sayBye" und einigen anderen "sayXXX" -Funktionen anstelle von Fensterobjekten zu schreiben. Tatsächlich möchten Sie im Client-Code möglicherweise nicht einmal wissen, dass es so etwas wie ein "Fenster" -Objekt gibt.
quelle
Erstaunlich, dass keine andere Person das Testen erwähnt hat.
Die spezielle "umbrochene" Zeile, die Sie ausgewählt haben
window.alert('hello')
, ist tatsächlich ein perfektes Beispiel dafür. Alles, was mit demwindow
Objekt zu tun hat, ist wirklich sehr, sehr schmerzhaft zu testen. Multiplizieren Sie dies mit 1000 in Ihrer Anwendung, und ich garantiere, dass die Entwickler das Testen irgendwann aufgeben werden. Andererseits ist es ziemlich einfach, diesayHello
Funktion mit einem Spion zu zerstören und zu testen, ob sie aufgerufen wurde.Ein praktischeres Beispiel - denn wer verwendet eigentlich
window.alert(...)
in der Produktion Code? - überprüft die Systemuhr. Dies würde beispielsweiseDateTime.Now
in .NET,time(...)
C / C ++ oderSystem.currentTimeMillis()
Java erfolgen. Sie möchten diese wirklich in eine Abhängigkeit einschließen, die Sie injizieren können, da sie nicht nur (fast) unmöglich zu verspotten sind, sondern auch schreibgeschützt und nicht deterministisch sind . Jeder Test, der eine Funktion oder Methode abdeckt, bei der die Systemuhrfunktion direkt verwendet wird, weist mit hoher Wahrscheinlichkeit intermittierende und / oder zufällige Fehler auf.Der eigentliche Wrapper ist eine 1-Zeilen-Funktion -
return DateTime.Now
- aber das ist alles, was Sie brauchen, um ein schlecht gestaltetes, nicht testbares Objekt sauber und testbar zu machen. Sie können den Wrapper durch eine gefälschte Uhr ersetzen und die Uhrzeit nach Belieben einstellen. Problem gelöst.quelle
Wie Doval sagte, versucht dieses Beispiel wahrscheinlich nur, Ihnen Funktionen vorzustellen. Ich bin allgemein, aber es ist nützlich. Insbesondere wenn Sie einige, aber nicht alle Argumente angeben und die anderen übergeben, können Sie aus einer allgemeineren Funktion eine fallspezifischere Funktion erstellen. Betrachten Sie als etwas triviales Beispiel eine Sortierfunktion, die ein Array zum Sortieren und eine Komparatorfunktion zum Sortieren benötigt. Durch die Angabe einer Komparatorfunktion, die mit einem numerischen Wert verglichen wird, kann eine sortByNumericalValue-Funktion erstellt werden, und Aufrufe dieser Funktion sind viel klarer und präziser.
quelle
Das Denken hinter Ihrer Frage scheint zu sein: "Warum nicht einfach
alert("Hello");
direkt schreiben ? Es ist ziemlich einfach."Die Antwort ist zum Teil, weil Sie nicht wirklich anrufen möchten
alert("Hello")
- Sie möchten nur Hallo sagen.Oder: Warum Kontakte auf Ihrem Telefon speichern, wenn Sie nur Telefonnummern wählen können? Weil Sie sich nicht alle diese Zahlen merken wollen; weil das Wählen von Nummern mühsam und fehleranfällig ist; weil sich die Zahl ändern könnte, aber es ist immer noch die gleiche Person am anderen Ende. Weil Sie Leute anrufen wollen , keine Nummern.
Dies wird unter Begriffen wie Abstraktion, Indirektion, "Verbergen von Implementierungsdetails" und sogar "Ausdruckscode" verstanden.
Die gleiche Überlegung gilt für die Verwendung von Konstanten, anstatt überall rohe Werte zu schreiben. Sie können schreiben Sie einfach
3.141592...
jedes Mal , wenn π brauchen, aber zum Glück gibt esMath.PI
.Wir könnten uns auch selbst anschauen
alert()
. Wen interessiert es, wie es diesen Alarmdialog erstellt und anzeigt? Sie möchten nur den Benutzer benachrichtigen. Zwischen dem Schreibenalert("Hello")
und dem Ändern der Pixel auf Ihrem Bildschirm gibt es einen tiefen, tiefen Stapel von Code und Hardware, wobei jede Ebene der nächsten mitteilt, was sie will, und die nächste Ebene sich um Details kümmert, bis die tiefstmögliche Ebene einige Bits in der Ebene umdreht Videospeicher.Sie möchten das alles wirklich nicht selbst tun müssen, nur um Hallo zu sagen.
Bei der Programmierung - eigentlich bei jeder Aufgabe - geht es darum, komplexe Probleme in überschaubare Teile zu unterteilen. Wenn Sie jeden Block lösen, erhalten Sie einen Baustein, und mit genügend einfachen Bausteinen können Sie große Dinge bauen.
Es ist Algebra.
quelle
Es ist eine gute Idee, die Berechnung von Werten (Ausdrücken) von der Ausführung von Aktionen (Anweisungen) getrennt zu halten . Wir wollen genau steuern, wo und wann Maßnahmen ergriffen werden (wie das Anzeigen von Nachrichten), aber bei der Berechnung von Werten arbeiten wir lieber auf einer abstrakteren Ebene und müssen uns nicht darum kümmern, wie diese Werte berechnet werden.
Eine Funktion, die nur einen Rückgabewert unter Verwendung der angegebenen Argumente berechnet, heißt pure .
Eine "Funktion", die eine Aktion ausführt, ist eigentlich eine Prozedur , die eine Wirkung hat .
Effekte, die während der Berechnung eines Wertes verursacht werden, werden als Nebenwirkungen bezeichnet . Es ist besser, sie nach Möglichkeit zu vermeiden ("Ich brauchte nur diesen String, ich wusste nicht, dass er die Datenbank hämmern würde!").
Um die Wahrscheinlichkeit von Nebenwirkungen zu minimieren, sollten wir vermeiden, zu viele Daten an unsere Verfahren zu senden oder Berechnungen anzustellen. Wenn eine Berechnung im Voraus durchgeführt werden muss, ist es normalerweise besser, sie separat in einer reinen Funktion durchzuführen und dann nur das erforderliche Ergebnis an die Prozedur zu übergeben. Dies hält den Zweck des Verfahrens klar und verringert die Wahrscheinlichkeit, dass es später als Teil einer Berechnung wiederverwendet wird (die reine Funktion kann stattdessen wiederverwendet werden).
Aus dem gleichen Grund sollten wir vermeiden, Ergebnisse innerhalb einer Prozedur zu verarbeiten. Es ist besser, das Ergebnis (falls vorhanden) unserer Aktion zurückzugeben und eine nachfolgende Verarbeitung mit reinen Funktionen durchzuführen.
Wenn wir diese Regeln befolgen, erhalten wir möglicherweise eine Prozedur wie die
sayHello
, die keine Daten benötigt und kein Ergebnis hat. Daher ist es die beste Schnittstelle, keine Argumente zu haben und keinen Wert zurückzugeben. Dies ist beispielsweise vorzuziehen, wenn Sie "console.log" mitten in einer Berechnung aufrufen.Um die Notwendigkeit von Effekten während der Berechnung zu verringern, können Berechnungen durchgeführt werden, die Prozeduren zurückgeben . z.B. Wenn wir uns für eine Aktion entscheiden müssen, kann eine reine Funktion eine Prozedur auswählen und zurückgeben, anstatt sie direkt auszuführen.
Um den Rechenaufwand bei Prozeduren zu verringern, können Prozeduren auch andere Prozeduren als Parameter verwenden (möglicherweise das Ergebnis einer Funktion). z.B. eine Reihe von Prozeduren nehmen und nacheinander ausführen.
quelle
setFoo
Anrufe empfehlen , da dies veränderbare Daten impliziert. Das Ändern des Inhalts von Variablen / Eigenschaften ist ein Effekt, der dazu führt, dass alle Berechnungen, die diese Daten verwenden, unrein werden. Ich würde keineexecute
Aufrufe per se empfehlen , aber ich würderunFoo
Verfahren zum Ausführen von Aktionen basierend auf ihren Argumenten empfehlen .Ich würde sagen, es ist eine Kombination der Antworten von @MichaelT und @Sleiman Jneidi.
Vielleicht gibt es eine Reihe von Stellen im Code, an denen Sie den Benutzer mit einer Hallo-Nachricht begrüßen möchten, damit Sie diese Idee in eine Methode packen. In der Methode können Sie es übersetzen oder ein einfaches 'Hallo' erweitern, indem Sie einen längeren Text anzeigen. Vielleicht möchten Sie auch ein nettes JQuery-Dialogfeld anstelle einer Warnung verwenden.
Der Punkt ist, dass sich die Implementierung an einem Ort befindet. Sie müssen nur den Code an einer Stelle ändern. (SayHello () ist vielleicht ein zu einfaches Beispiel)
quelle