Geben Sie in Javascript zurück, wie es funktioniert. Expressives JavaScript: Funktionen. Lokale und globale Variablen

💖 Gefällt es dir? Teilen Sie den Link mit Ihren Freunden

Sprunganweisungen und Ausnahmebehandlung

Eine weitere Kategorie von JavaScript-Operatoren sind Sprungoperatoren. Wie der Name schon sagt, bewirken diese Operatoren, dass der JavaScript-Interpreter an eine andere Stelle im Programmcode springt. Die break-Anweisung bewirkt, dass der Interpreter zum Ende einer Schleife oder einer anderen Anweisung springt. Die continue-Anweisung bewirkt, dass der Interpreter den Rest des Schleifenkörpers überspringt, zum Anfang der Schleife zurückspringt und mit der Ausführung einer neuen Iteration beginnt. JavaScript verfügt über die Möglichkeit, Anweisungen mit Namen zu kennzeichnen, sodass Break- und Continue-Anweisungen explizit angeben können, zu welcher Schleife oder anderen Anweisung sie gehören.

Die Return-Anweisung bewirkt, dass der Interpreter von der aufgerufenen Funktion zu dem Punkt zurückspringt, an dem sie aufgerufen wurde, und den Wert des Aufrufs zurückgibt. Die throw-Anweisung löst eine Ausnahme aus und soll in Verbindung mit try/catch/finally-Anweisungen funktionieren, die einen Block definieren Programmcode um die Ausnahme zu behandeln. Hierbei handelt es sich um einen ziemlich komplexen Typ eines Sprungoperators: Wenn eine Ausnahme auftritt, springt der Interpreter zum nächstgelegenen einschließenden Ausnahmehandler, der sich in derselben Funktion oder höher im Rückgabestapel der aufgerufenen Funktion befinden kann.

Alle diese Sprungoperatoren werden in den folgenden Unterabschnitten ausführlicher beschrieben.

Anweisungszeichen

Jede Anweisung kann mit einem Bezeichner und einem Doppelpunkt markiert werden:

ID: Anweisung

Indem Sie eine Anweisung markieren, geben Sie ihr einen Namen, der dann an einer beliebigen Stelle im Programm als Referenz verwendet werden kann. Sie können jede Anweisung markieren, es ist jedoch nur sinnvoll, Anweisungen zu markieren, die einen Hauptteil haben, wie z. B. Schleifen und bedingte Anweisungen.

Indem Sie einer Schleife einen Namen zuweisen, kann dieser dann in break- und continue-Anweisungen, innerhalb einer Schleife zum Verlassen dieser Schleife oder zum Springen zum Anfang der Schleife zur nächsten Iteration verwendet werden. Die Anweisungen „break“ und „continue“ sind die einzigen JavaScript-Anweisungen, die Beschriftungen enthalten können – wir werden sie später ausführlicher behandeln. Das Folgende ist ein Beispiel für eine while-Anweisung mit einer Bezeichnung und eine continue-Anweisung, die diese Bezeichnung verwendet:

Mainloop: while (token != null) ( // Programmcode weggelassen... continue mainloop; // Zur nächsten Iteration der benannten Schleife wechseln)

Der als Anweisungsbezeichnung verwendete Bezeichner kann jeder gültige JavaScript-Bezeichner außer einem reservierten Wort sein. Beschriftungsnamen werden von Variablen- und Funktionsnamen getrennt, sodass Bezeichner, die mit Variablen- oder Funktionsnamen übereinstimmen, als Beschriftungen verwendet werden können.

Anweisungsbeschriftungen werden nur innerhalb der Anweisungen definiert, auf die sie sich beziehen (und natürlich innerhalb der darin verschachtelten Anweisungen). Verschachtelte Anweisungen können nicht mit denselben Bezeichnern wie die sie enthaltenden Anweisungen gekennzeichnet werden, aber zwei unabhängige Anweisungen können mit derselben Bezeichnung versehen werden. Markierte Anweisungen können erneut markiert werden. Das heißt, jede Anweisung kann viele Beschriftungen haben.

break-Anweisung

Die break-Anweisung bewirkt, dass die innerste Schleife oder switch-Anweisung sofort beendet wird. Wir haben bereits Beispiele für die Verwendung der break-Anweisung innerhalb einer switch-Anweisung gesehen. In Schleifen wird es normalerweise verwendet, um die Schleife sofort zu verlassen, wenn die Schleife aus irgendeinem Grund beendet werden muss.

Wenn eine Schleife über sehr komplexe Beendigungsbedingungen verfügt, ist es oft einfacher, diese Bedingungen mithilfe einer break-Anweisung zu implementieren, als zu versuchen, sie in einem einzigen Schleifenbedingungsausdruck auszudrücken. Im folgenden Beispiel wird versucht, ein Array-Element mit einem bestimmten Wert zu finden. Die Schleife endet normal, wenn das Ende des Arrays erreicht ist, oder mit einer Break-Anweisung, sobald der gesuchte Wert gefunden wurde:

Var arr = ["a", "b", "c", "d", "d"], Ergebnis; für (var i = 0; i

In JavaScript können Sie den Namen des Labels nach dem Schlüsselwort break (Bezeichner ohne Doppelpunkt) angeben:

break label_name;

Wenn eine Break-Anweisung mit einer Bezeichnung verwendet wird, springt sie zum Ende der benannten Anweisung oder beendet deren Ausführung. Wenn keine Anweisung mit der angegebenen Bezeichnung vorhanden ist, führt der Versuch, diese Form der break-Anweisung zu verwenden, zu einem Syntaxfehler. Die benannte Anweisung muss keine Schleifen- oder Switch-Anweisung sein. Eine Break-Anweisung mit einer Bezeichnung kann aus jeder enthaltenden Anweisung ausbrechen. Eine Wrapper-Anweisung kann sogar ein einfacher, in geschweifte Klammern eingeschlossener Befehlsblock sein, der ausschließlich der Kennzeichnung dient.

Zwischen dem Schlüsselwort „break“ und dem Labelnamen kann kein Zeilenumbruchzeichen eingefügt werden. Dies liegt daran, dass der JavaScript-Interpreter fehlende Semikolons automatisch einfügt: Wenn Sie eine Codezeile zwischen dem Schlüsselwort „break“ und der folgenden Beschriftung aufteilen, geht der Interpreter davon aus, dass Sie die einfache Form der Anweisung ohne die Beschriftung gemeint haben, und fügt ein Semikolon hinzu.

Eine gekennzeichnete break-Anweisung ist nur dann erforderlich, wenn Sie die Ausführung einer Anweisung unterbrechen möchten, die nicht die nächste einschließende Schleife oder switch-Anweisung ist.

Betreiber fortfahren

Die continue-Anweisung ähnelt der break-Anweisung. Anstatt die Schleife zu verlassen, startet die continue-Anweisung jedoch eine neue Iteration der Schleife. Die Syntax der continue-Anweisung ist genauso einfach wie die Syntax der break-Anweisung. Die continue-Anweisung kann auch mit einem Label verwendet werden.

Die continue-Anweisung kann sowohl in der Form ohne Label als auch mit Label nur im Rumpf einer Schleife verwendet werden. Die Verwendung an anderer Stelle führt zu einem Syntaxfehler. Wenn die continue-Anweisung ausgeführt wird, wird die aktuelle Iteration der Schleife unterbrochen und die nächste beginnt. Für verschiedene Typen Zyklen bedeutet dies verschiedene Dinge:

    In einer While-Schleife wird der am Anfang der Schleife angegebene Ausdruck erneut überprüft. Wenn er wahr ist, wird der Schleifenkörper von Anfang an ausgeführt.

    Eine do/while-Schleife springt zum Ende der Schleife, wo die Bedingung erneut überprüft wird, bevor die Schleife erneut ausgeführt wird.

    Die for-Schleife wertet den Inkrementausdruck aus und wertet den Testausdruck erneut aus, um zu bestimmen, ob die nächste Iteration durchgeführt werden soll.

    In einer for/in-Schleife beginnt die Schleife von vorne, indem sie die angegebene Variable dem Namen der nächsten Eigenschaft zuweist.

Beachten Sie die Unterschiede im Verhalten der continue-Anweisung in while- und for-Schleifen. Die while-Schleife kehrt direkt in ihren Zustand zurück und for-Schleife wertet zunächst den Inkrementausdruck aus und kehrt dann zur Bedingung zurück. Das folgende Beispiel zeigt die Verwendung einer continue-Anweisung ohne Beschriftung, um die aktuelle Schleifeniteration für gerade Zahlen zu verlassen:

Var-Summe = 0; // Berechnen Sie die Summe der ungeraden Zahlen von 0 - 10 für (var i = 0; i

Die continue-Anweisung kann wie break in verschachtelten Schleifen in einer Form verwendet werden, die eine Beschriftung enthält. Dann ist die neu gestartete Schleife nicht unbedingt eine Schleife, die die continue-Anweisung direkt enthält. Darüber hinaus sind wie bei break keine Zeilenumbrüche zwischen dem Schlüsselwort continue und dem Labelnamen zulässig.

return-Anweisung

Ein Funktionsaufruf ist ein Ausdruck und hat wie alle Ausdrücke einen Wert. Die return-Anweisung innerhalb von Funktionen wird verwendet, um den von der Funktion zurückgegebenen Wert zu bestimmen. Die Return-Anweisung kann nur im Hauptteil einer Funktion erscheinen. Das Vorhandensein an anderer Stelle ist ein Syntaxfehler. Wenn eine Return-Anweisung ausgeführt wird, gibt die Funktion den Wert des Ausdrucks an das aufrufende Programm zurück. Zum Beispiel:

Wenn eine Funktion beim Aufruf keine Return-Anweisung hat, führt der Interpreter die Anweisungen im Funktionskörper nacheinander aus, bis das Ende der Funktion erreicht ist, und gibt dann die Kontrolle an das Programm zurück, das sie aufgerufen hat. In diesem Fall gibt der aufrufende Ausdruck undefiniert zurück. Die return-Anweisung ist oft letzte Anweisung in der Funktion, aber das ist völlig optional: Die Funktion gibt die Kontrolle an das aufrufende Programm zurück, sobald eine Return-Anweisung erreicht wird, auch wenn ihr andere Anweisungen im Funktionskörper folgen.

Die return-Anweisung kann auch ohne Ausdruck verwendet werden. In diesem Fall bricht sie die Funktion einfach ab und gibt undefiniert an das aufrufende Programm zurück. Zum Beispiel:

Funktion myFun(arr) ( // Wenn das Array negative Zahlen enthält, brechen Sie die Funktion ab für (var i = 0; i

throw-Anweisung

Eine Ausnahme ist ein Signal, das darauf hinweist, dass eine Ausnahmesituation oder ein Fehler aufgetreten ist. Eine Ausnahme auslösen ist eine Möglichkeit, einen solchen Fehler oder eine solche Ausnahme zu signalisieren. Eine Ausnahme abzufangen bedeutet, sie zu verarbeiten, d. h. Ergreifen Sie die erforderlichen oder angemessenen Maßnahmen, um die Ausnahme zu beheben.

IN JavaScript-Ausnahmen wird ausgelöst, wenn ein Laufzeitfehler auftritt und wenn das Programm ihn explizit mithilfe einer throw-Anweisung auslöst. Ausnahmen werden mithilfe von try/catch/finally-Anweisungen abgefangen, die später beschrieben werden.

Die throw-Anweisung hat die folgende Syntax:

Wurfausdruck;

Das Ergebnis des Ausdrucks kann ein Wert beliebigen Typs sein. Der throw-Anweisung kann eine Zahl übergeben werden, die einen Fehlercode darstellt, oder eine Zeichenfolge, die den Text der Fehlermeldung enthält. Der JavaScript-Interpreter löst Ausnahmen mithilfe einer Instanz der Error-Klasse einer seiner Unterklassen aus, und Sie können einen ähnlichen Ansatz verwenden. Das Error-Objekt verfügt über eine Eigenschaft Name, das die Art des Fehlers und die Eigenschaft definiert Nachricht, enthält die an die Konstruktorfunktion übergebene Zeichenfolge. Das Folgende ist ein Beispiel für eine Funktion, die ein Error-Objekt auslöst, wenn sie mit einem ungültigen Argument aufgerufen wird:

// Zahlenfaktorielle Funktion function factial(number) ( // Wenn das Eingabeargument kein gültiger Wert ist, // wird eine Ausnahme ausgelöst! if (number 1; i *= number, number--); /* leerer Schleifenkörper */ return i ; ) console.log("5! = ", factial(5)); console.log("-3! = ", factial(-3));

Wenn eine Ausnahme ausgelöst wird, unterbricht der JavaScript-Interpreter sofort die normale Programmausführung und springt zum nächstgelegenen Ausnahmebehandler. Ausnahmehandler verwenden die try/catch/finally Catch-Klausel, die im nächsten Abschnitt beschrieben wird.

Wenn der Codeblock, in dem die Ausnahme aufgetreten ist, kein entsprechendes Catch-Konstrukt hat, untersucht der Interpreter den nächsten äußeren Codeblock und prüft, ob ihm ein Ausnahmehandler zugeordnet ist. Dies wird so lange fortgesetzt, bis ein Handler gefunden wird.

Wenn eine Ausnahme in einer Funktion ausgelöst wird, die kein try/catch/finally-Konstrukt zur Behandlung enthält, wird die Ausnahme bis zu dem Code weitergegeben, der die Funktion aufgerufen hat. Auf diese Weise werden Ausnahmen durch die lexikalische Struktur weitergegeben JavaScript-Methoden den Aufrufstapel nach oben. Wenn nie ein Ausnahmehandler gefunden wird, wird die Ausnahme als Fehler behandelt und dem Benutzer gemeldet.

try/catch/finally konstruieren

Das try/catch/finally-Konstrukt implementiert den Ausnahmebehandlungsmechanismus in JavaScript. Die try-Anweisung in diesem Konstrukt definiert einfach einen Codeblock, in dem Ausnahmen behandelt werden. Auf den Try-Block folgt eine Catch-Anweisung mit einem Block von Anweisungen, die aufgerufen werden, wenn irgendwo im Try-Block eine Ausnahme auftritt. Auf die Catch-Anweisung folgt ein Final-Block, der den endgültigen Code enthält, der garantiert ausgeführt wird, unabhängig davon, was im Try-Block passiert.

Sowohl der Catch-Block als auch der Final-Block sind optional, aber mindestens einer von ihnen muss nach dem Try-Block vorhanden sein. Versuchen, fangen und schließlich den Anfang und das Ende blockieren Geschweifte Klammern. Dies ist ein erforderlicher Teil der Syntax und kann nicht weggelassen werden, auch wenn dazwischen nur eine Anweisung steht.

Der folgende Ausschnitt veranschaulicht die Syntax und den Zweck des try/catch/finally-Konstrukts:

Try ( // Dieser Code läuft normalerweise von Anfang bis Ende reibungslos. // Aber irgendwann kann es passieren, dass er eine Ausnahme auslöst // entweder direkt mit der throw-Anweisung oder indirekt // durch Aufrufen einer Methode, die die Ausnahme auslöst. ) Catch ( ex) ( // Die Anweisungen in diesem Block werden genau dann ausgeführt, wenn eine Ausnahme // im try-Block auftritt. Diese Anweisungen können die lokale Variable ex verwenden, die // auf ein Error-Objekt oder einen anderen im Throw angegebenen Wert verweist -Anweisung. // Dieser Block kann die Ausnahme entweder auf irgendeine Weise behandeln, // sie ignorieren, während etwas anderes ausgeführt wird, oder die Ausnahme // mithilfe einer Throw-Anweisung erneut auslösen. ) final ( // Dieser Block enthält Anweisungen, die immer ausgeführt werden , unabhängig davon, // was im Try-Block passiert ist. Sie werden ausgeführt, wenn der Try-Block abgeschlossen ist: // 1) wie üblich, nachdem das Ende des Blocks erreicht wurde // 2) aufgrund einer Break-, Continue- oder Return-Anweisung / / 3) mit der Ausnahme, die von der im obigen Catch-Block behandelt wird // 4) mit einer nicht abgefangenen Ausnahme, die sich weiterhin // auf höhere Ebenen ausbreitet)

Beachten Sie, dass auf das Schlüsselwort „catch“ ein Bezeichner in Klammern folgt. Dieser Bezeichner ähnelt einem Funktionsparameter. Wenn eine Ausnahme abgefangen wird, wird dieser Parameter der Ausnahme zugewiesen (z. B. einem Fehlerobjekt). Im Gegensatz zu einer regulären Variablen ist der mit einer Catch-Anweisung verknüpfte Bezeichner nur im Hauptteil des Catch-Blocks vorhanden.

Das Folgende ist ein realistischeres Beispiel für ein Try/Catch-Konstrukt. Es ruft die im vorherigen Beispiel definierte Methode „factorial()“ und die JavaScript-Methoden „prompt()“ und „alert()“ des Clients auf, um die Eingabe und Ausgabe zu organisieren:

Versuchen Sie ( // Fordern Sie eine Nummer vom Benutzer an var n = Number(prompt("Enter positive Zahl", "")); // Berechne die Fakultät einer Zahl unter der Annahme //, dass die Eingabedaten korrekt sind var f = factial(n); // Das Ergebnis drucken warning(n + "! = " + f); ) Catch (Ex) ( // Wenn die Daten falsch sind, wird die Kontrolle hierher übertragen. Alert(Ex); // Benachrichtigen Sie den Benutzer über den Fehler. )

Wenn der Benutzer eine negative Zahl eingibt, erscheint eine Warnmeldung:

Dies ist ein Beispiel für ein Try/Catch-Konstrukt ohne Final-Klausel. Obwohl „finally“ nicht so oft verwendet wird wie „cat“, ist es manchmal dennoch nützlich. Die Ausführung des „final“-Blocks ist garantiert, wenn zumindest ein Teil des „try“-Blocks ausgeführt wurde, unabhängig davon, wie der Code im „try“-Block die Ausführung abgeschlossen hat. Diese Funktion wird normalerweise verwendet, um abschließende Vorgänge nach der Ausführung von Code in einer Try-Fortsetzung durchzuführen.

In einer normalen Situation erreicht die Steuerung das Ende des Try-Blocks und wechselt dann zum Final-Block, der die erforderlichen Abschlussoperationen ausführt. Wenn die Steuerung einen Try-Block aufgrund einer Return-, Continue- oder Break-Anweisung verlässt, wird der Final-Block ausgeführt, bevor die Steuerung an eine andere Stelle übertragen wird.

Wenn in einem Try-Block eine Ausnahme auftritt und es einen entsprechenden Catch-Block zur Behandlung gibt, geht die Steuerung zunächst an den Catch-Block und dann an den Final-Block über. Wenn kein lokaler Catch-Block vorhanden ist, geht die Steuerung zunächst an den Final-Block über und wechselt dann zum nächstgelegenen äußeren Catch-Block, der die Ausnahme behandeln kann.

Wenn der „finally“-Block selbst die Kontrolle über eine Return-, Continue-, Break- oder Throw-Anweisung oder durch den Aufruf einer Methode, die eine Ausnahme auslöst, überträgt, wird der ausstehende Übertragungsbefehl abgebrochen und ein neuer ausgeführt. Wenn beispielsweise ein „finally“-Block eine Ausnahme auslöst, ersetzt diese Ausnahme alle zuvor ausgelösten Ausnahmen.

Funktionen sind einer der wichtigsten Codebausteine ​​in JavaScript.

Funktionen bestehen aus einer Reihe von Befehlen und führen normalerweise eine bestimmte Aufgabe aus (z. B. Zahlen summieren, Wurzeln berechnen usw.).

In einer Funktion platzierter Code wird erst nach einem expliziten Aufruf dieser Funktion ausgeführt.

Funktionen deklarieren

1. Syntax:

//Deklaration der Funktion functionFunctionname(ln1, ln2)( Funktionscode) //Aufruf der FunktionFunctionname(ln1,lr2);

2. Syntax:

//Deklaration der Funktion var function name=function(ln1, ln2)(Function code) //Aufruf der Funktion function name(ln1,lr2);

Funktionsname gibt den Namen der Funktion an. Jede Funktion auf der Seite muss einen eindeutigen Namen haben. Der Funktionsname muss in lateinischen Buchstaben angegeben werden und darf nicht mit Zahlen beginnen.

ln1 und ln2 sind Variablen oder Werte, die an die Funktion übergeben werden können. An jede Funktion kann eine unbegrenzte Anzahl von Variablen übergeben werden.

Bitte beachten Sie: Auch wenn der Funktion keine Variablen übergeben werden, vergessen Sie nicht, nach dem Funktionsnamen Klammern „()“ einzufügen.

Bitte beachten Sie, dass bei Funktionsnamen in JavaScript die Groß-/Kleinschreibung beachtet wird.

Beispiel einer JavaScript-Funktion

Die Funktion messageWrite() im Beispiel unten wird erst ausgeführt, nachdem auf die Schaltfläche geklickt wurde.

Beachten Sie, dass in diesem Beispiel das onclick-Ereignis verwendet wird. JavaScript-Ereignisse wird später in diesem Lehrbuch ausführlich besprochen.

// Die Funktion schreibt Text in die Seitenfunktion messageWrite() ( document.write("Dieser Text wurde mit JavaScript auf die Seite geschrieben!"); )

Übergabe von Variablen an Funktionen

Sie können eine unbegrenzte Anzahl von Variablen an Funktionen übergeben.

Bitte beachten Sie: Alle Manipulationen mit Variablen innerhalb von Funktionen werden tatsächlich nicht an den Variablen selbst, sondern an ihrer Kopie durchgeführt, sodass sich der Inhalt der Variablen selbst durch die Ausführung von Funktionen nicht ändert.

/* Definieren wir eine Funktion, die 10 zur übergebenen Variablen hinzufügt und das Ergebnis auf der Seite anzeigt */ function plus(a)( a=a+10; document.write("Funktionsausgabe: " + a+"
"); ) var a=25; document.write("Der Wert der Variablen vor dem Funktionsaufruf: "+a+"
"); // Rufen Sie die Funktion auf, indem Sie ihr die Variable a plus(a); übergeben. document.write("Wert der Variablen nach Aufruf der Funktion: "+a+"
");

Schnellansicht

Um über eine Funktion auf eine globale Variable zuzugreifen und nicht über eine Kopie davon, verwenden Sie window.variable_name.

Funktion plus(a)( window.a=a+10; ) var a=25; document.write("Der Wert der Variablen vor dem Funktionsaufruf: „+a+“
"); plus(a); document.write("Wert der Variablen nach Aufruf der Funktion: "+a+"
");

Schnellansicht

Return-Befehl

Mit dem Return-Befehl können Sie Werte von Funktionen zurückgeben.

//Die Summenfunktion gibt die Summe der an sie übergebenen Variablen zurück. Funktion sum(v1,v2)( return v1+v2; ) document.write("5+6=" + sum(5,6) + "
"); document.write("10+4=" + sum(10,4) + "
");

Schnellansicht

Integrierte Funktionen

Neben benutzerdefinierten Funktionen verfügt JavaScript auch über integrierte Funktionen.

Mit der integrierten Funktion isFinite können Sie beispielsweise überprüfen, ob der übergebene Wert eine gültige Zahl ist.

Document.write(isFinite(40)+"
"); document.write(isFinite(-590)+"
"); document.write(isFinite(90.33)+"
"); document.write(isFinite(NaN)+"
"); document.write(isFinite("Dies ist ein String")+"
");

Schnellansicht

Beachten Sie: volle Liste Integrierte JavaScript-Funktionen finden Sie in unserem .

Lokale und globale Variablen

Variablen, die innerhalb von Funktionen erstellt werden, werden lokale Variablen genannt. Sie können auf solche Variablen nur innerhalb der Funktionen zugreifen, in denen sie definiert wurden.

Nachdem der Funktionscode die Ausführung abgeschlossen hat, werden solche Variablen zerstört. Dies bedeutet, dass Variablen mit demselben Namen in verschiedenen Funktionen definiert werden können.

Variablen, die außerhalb des Funktionscodes erstellt werden, werden globale Variablen genannt; auf solche Variablen kann von überall im Code aus zugegriffen werden.

Wenn Sie eine Variable ohne Variable innerhalb einer Funktion deklarieren, wird sie ebenfalls global.

Globale Variablen werden erst zerstört, nachdem die Seite geschlossen wurde.

//Globale Variablen var1 und var2 deklarieren var var1="var1 existiert"; var var2; function func1() ( //Var2 einen Wert innerhalb der Funktion func1 var var2="var2 existiert"; ) zuweisen //Von einer anderen Funktion aus den Inhalt der Variablen var1 und var2 auf die Seite drucken Funktion func2() ( //Drucken der Inhalt der Variablen var1 document.write( var1 + "
"); //Den Inhalt der Variablen var2 ausgeben document.write(var2); )

Schnellansicht

Beachten Sie, dass var2 bei der Ausgabe auf dem Bildschirm einen leeren Wert hat, da func1 mit der lokalen „Version“ von var2 arbeitet.

Verwendung anonymer Funktionen

Funktionen, die bei der Deklaration keinen Namen enthalten, werden als anonym bezeichnet.

Anonyme Funktionen werden grundsätzlich nicht so deklariert, dass sie anschließend wie reguläre Funktionen aus dem Code aufgerufen werden, sondern dass sie als Parameter an andere Funktionen übergeben werden.

Funktion arrMap(arr,func)( var res=new Array; for (var i=0;i target) return null; else return find(start + 5, "(" + History + " + 5)") || find (start * 3, "(" + History + " * 3)"); ) return find(1, "1"); ) console.log(findSolution(24)); // → (((1 * 3) + 5) * 3)

Dieses Beispiel findet nicht unbedingt die kürzeste Lösung – es wird von jeder erfüllt. Ich erwarte nicht, dass Sie sofort verstehen, wie das Programm funktioniert. Aber lassen Sie uns diese großartige Übung im rekursiven Denken verstehen.

Die innere Funktion find führt eine Rekursion durch. Es benötigt zwei Argumente – die aktuelle Zahl und eine Zeichenfolge, die eine Aufzeichnung darüber enthält, wie wir zu dieser Zahl gekommen sind. Und es gibt entweder eine Zeichenfolge zurück, die unsere Schrittfolge zeigt, oder null.

Zu diesem Zweck führt die Funktion eine der folgenden Aktionen aus: drei Aktionen. Wenn die angegebene Zahl dem Ziel entspricht, ist die aktuelle Geschichte genau der Weg, dieses zu erreichen, also kehrt sie zurück. Wenn die angegebene Zahl größer als das Ziel ist, macht es keinen Sinn, weiter zu multiplizieren und zu addieren, da sie nur zunimmt. Und wenn wir das Ziel noch nicht erreicht haben, probiert die Funktion beide möglichen Pfade aus, beginnend mit der angegebenen Zahl. Sie ruft sich selbst zweimal herbei, einmal mit jeder Methode. Wenn der erste Aufruf nicht null zurückgibt, wird er zurückgegeben. In einem anderen Fall wird der zweite zurückgegeben.

Um besser zu verstehen, wie die Funktion ihre gewünschte Wirkung erzielt, schauen wir uns die Aufrufe an, die sie durchführt, um eine Lösung für die Zahl 13 zu finden.

Find(1, "1") find(6, "(1 + 5)") find(11, "((1 + 5) + 5)") find(16, "(((1 + 5) + 5 ) + 5)") zu groß find(33, "(((1 + 5) + 5) * 3)") zu groß find(18, "((1 + 5) * 3)") zu groß find( 3, "(1 * 3)") find(8, "((1 * 3) + 5)") find(13, "(((1 * 3) + 5) + 5)") gefunden!

Die Einrückung zeigt die Tiefe des Aufrufstapels. Beim ersten Mal ruft sich die Suchfunktion zweimal auf, um Lösungen zu prüfen, die mit (1 + 5) und (1 * 3) beginnen. Der erste Aufruf sucht nach einer Lösung, die mit (1 + 5) beginnt, und überprüft mithilfe der Rekursion alle Lösungen, die eine Zahl ergeben, die kleiner oder gleich der erforderlichen Zahl ist. Findet es nicht und gibt null zurück. Dann ist der Operator || und fährt mit einem Funktionsaufruf fort, der die Option (1 * 3) untersucht. Wir haben hier Glück, denn im dritten rekursiven Aufruf erhalten wir 13. Dieser Aufruf gibt einen String zurück, und jeder der || Auf dem Weg dorthin passiert es diese Linie höher, was zur Rückgabe einer Lösung führt.

Wachsende Funktionen Es gibt zwei mehr oder weniger natürliche Möglichkeiten, Funktionen in ein Programm einzuführen.

Die erste besteht darin, dass Sie mehrmals ähnlichen Code schreiben. Dies sollte vermieden werden – mehr Code bedeutet mehr Raum für Fehler und mehr Lesematerial für diejenigen, die das Programm verstehen möchten. Wir nehmen also eine wiederkehrende Funktionalität, geben ihr einen guten Namen und fügen sie in eine Funktion ein.

Der zweite Weg besteht darin, dass Sie einen Bedarf an einer neuen Funktionalität entdecken, die es wert ist, darin untergebracht zu werden separate Funktion. Sie beginnen mit dem Namen der Funktion und schreiben dann ihren Hauptteil. Sie können sogar damit beginnen, den Code zu schreiben, der die Funktion verwendet, bevor die Funktion selbst definiert wurde.

Wie schwierig es für Sie ist, eine Funktion zu benennen, zeigt, wie gut Sie ihre Funktionsweise verstehen. Nehmen wir ein Beispiel. Wir müssen ein Programm schreiben, das zwei Zahlen ausgibt, die Anzahl der Kühe und Hühner auf dem Bauernhof, gefolgt von den Wörtern „Kühe“ und „Hühner“. Sie müssen den Zahlen davor Nullen hinzufügen, sodass jede genau drei Positionen einnimmt.

007 Kühe 011 Hühner

Offensichtlich benötigen wir eine Funktion mit zwei Argumenten. Beginnen wir mit dem Codieren.
// FarmInventory-Funktion drucken printFarmInventory(kühe, Hühner) ( var cowString = String(kühe); while (cowString.length< 3) cowString = "0" + cowString; console.log(cowString + " Коров"); var chickenString = String(chickens); while (chickenString.length < 3) chickenString = "0" + chickenString; console.log(chickenString + " Куриц"); } printFarmInventory(7, 11);

Wenn wir .length zu einem String hinzufügen, erhalten wir seine Länge. Es stellt sich heraus, dass die while-Schleifen den Zahlen führende Nullen hinzufügen, bis eine Zeile mit 3 Zeichen entsteht.

Bereit! Aber gerade als wir dem Bauern den Code schicken wollten (natürlich zusammen mit einem saftigen Scheck), ruft er an und teilt uns mit, dass er Schweine auf seinem Bauernhof hat und ob wir ihm die Anzahl der Schweine anzeigen könnten Programm?

Natürlich ist es möglich. Aber wenn wir anfangen, den Code aus diesen vier Zeilen zu kopieren und einzufügen, wird uns klar, dass wir innehalten und nachdenken müssen. Es muss einen besseren Weg geben. Wir versuchen das Programm zu verbessern:

// Ausgabe WITH Adding Zeros AND Labels function printZeroPaddedWithLabel(number, label) ( var numberString = String(number); while (numberString.length< 3) numberString = "0" + numberString; console.log(numberString + " " + label); } // вывестиИнвентаризациюФермы function printFarmInventory(cows, chickens, pigs) { printZeroPaddedWithLabel(cows, "Коров"); printZeroPaddedWithLabel(chickens, "Куриц"); printZeroPaddedWithLabel(pigs, "Свиней"); } printFarmInventory(7, 11, 3);

Funktioniert! Aber der Name printZeroPaddedWithLabel ist etwas seltsam. Es kombiniert drei Dinge – Ausgabe, Hinzufügen von Nullen und eine Beschriftung – in einer Funktion. Anstatt ein ganzes sich wiederholendes Fragment in eine Funktion einzufügen, wollen wir ein Konzept hervorheben:

// Zero-Funktion hinzufügen zeroPad(number, width) ( var string = String(number); while (string.length< width) string = "0" + string; return string; } // вывестиИнвентаризациюФермы function printFarmInventory(cows, chickens, pigs) { console.log(zeroPad(cows, 3) + " Коров"); console.log(zeroPad(chickens, 3) + " Куриц"); console.log(zeroPad(pigs, 3) + " Свиней"); } printFarmInventory(7, 16, 3);

Eine Funktion mit einem schönen, klaren Namen „zeroPad“ erleichtert das Verständnis des Codes. Und es kann in vielen Situationen eingesetzt werden, nicht nur in unserem Fall. Beispielsweise um formatierte Tabellen mit Zahlen anzuzeigen.

Wie intelligent und vielseitig sollten die Funktionen sein? Wir können eine einfache Funktion schreiben, die eine Zahl an bis zu drei Stellen mit Nullen auffüllt, oder eine anspruchsvolle Allzweckfunktion zum Formatieren von Zahlen, die Brüche, negative Zahlen, Punktausrichtung, Auffüllen usw. unterstützt.

Eine gute Faustregel besteht darin, nur Funktionen hinzuzufügen, von denen Sie wissen, dass sie nützlich sind. Manchmal ist es verlockend, universelle Frameworks für jeden noch so kleinen Bedarf zu erstellen. Widerstehen Sie ihm. Sie werden die Arbeit nie zu Ende bringen, sondern am Ende nur eine Menge Code schreiben, den niemand verwenden wird.

Funktionen und Nebenwirkungen Funktionen können grob in solche unterteilt werden, die wegen ihrer Nebenwirkungen aufgerufen werden, und solche, die aufgerufen werden, um einen bestimmten Wert zu erzielen. Natürlich ist es auch möglich, diese Eigenschaften in einer Funktion zu kombinieren.

Die erste Hilfsfunktion im Farmbeispiel, printZeroPaddedWithLabel, wird aufgerufen, weil sie einen Nebeneffekt hat: Sie druckt eine Zeichenfolge. Das zweite, ZeroPad, wegen des Rückgabewerts. Und es ist kein Zufall, dass die zweite Funktion häufiger nützlich ist als die erste. Funktionen, die Werte zurückgeben, lassen sich einfacher miteinander kombinieren als Funktionen, die Nebenwirkungen erzeugen.

Eine reine Funktion ist eine spezielle Art von Wert zurückgebenden Funktion, die nicht nur keine Nebenwirkungen hat, sondern auch nicht von den Nebenwirkungen des restlichen Codes abhängt – sie funktioniert beispielsweise nicht mit globalen Variablen, die versehentlich gelöscht werden könnten woanders geändert. Eine reine Funktion gibt, wenn sie mit denselben Argumenten aufgerufen wird, dasselbe Ergebnis zurück (und macht nichts anderes) – was ganz nett ist. Es ist einfach, mit ihr zu arbeiten. Ein Aufruf einer solchen Funktion kann gedanklich durch das Ergebnis ihrer Arbeit ersetzt werden, ohne die Bedeutung des Codes zu ändern. Wenn Sie eine solche Funktion testen möchten, können Sie sie einfach aufrufen und sicherstellen, dass sie, wenn sie in einem bestimmten Kontext funktioniert, in jedem Kontext funktioniert. Weniger reine Funktionen können abhängig von vielen Faktoren unterschiedliche Ergebnisse liefern und Nebenwirkungen haben, die schwer zu testen und zu erklären sind.

Sie sollten sich jedoch nicht schämen, Funktionen zu schreiben, die nicht völlig rein sind, oder mit der Bereinigung des heiligen Codes solcher Funktionen zu beginnen. Nebenwirkungen sind oft von Vorteil. Es gibt keine Möglichkeit, eine saubere Version der Funktion console.log zu schreiben, und diese Funktion ist sehr nützlich. Einige Vorgänge lassen sich anhand von Nebenwirkungen leichter ausdrücken.

Zusammenfassung In diesem Kapitel wurde Ihnen gezeigt, wie Sie Ihre eigenen Funktionen schreiben. Wann Stichwort Die Funktion wird als Ausdruck verwendet und gibt einen Zeiger auf den Funktionsaufruf zurück. Bei Verwendung als Anweisung können Sie eine Variable deklarieren, indem Sie ihr einen Funktionsaufruf zuweisen.

Der Schlüssel zum Verständnis von Funktionen ist der lokale Geltungsbereich. Innerhalb einer Funktion deklarierte Parameter und Variablen sind für diese lokal, werden bei jedem Aufruf neu erstellt und sind von außen nicht sichtbar. Innerhalb einer anderen Funktion deklarierte Funktionen haben Zugriff auf deren Gültigkeitsbereich.

Es ist sehr nützlich, die verschiedenen von einem Programm ausgeführten Aufgaben in Funktionen zu unterteilen. Sie müssen sich nicht wiederholen; Funktionen machen Code lesbarer, indem sie ihn in sinnvolle Teile unterteilen, so wie Kapitel und Abschnitte eines Buches dabei helfen, normalen Text zu organisieren.

ÜbungenMinimum Im vorherigen Kapitel haben wir die Funktion Math.min erwähnt, die das kleinste ihrer Argumente zurückgibt. Jetzt können wir selbst eine solche Funktion schreiben. Schreiben Sie eine Min-Funktion, die zwei Argumente akzeptiert und das Minimum davon zurückgibt.

Console.log(min(0, 10)); // → 0 console.log(min(0, -10)); // → -10

Rekursion Wir haben gesehen, dass der Operator % (Modulo) verwendet werden kann, um zu bestimmen, ob eine Zahl (%2) gerade ist. Hier ist eine andere Möglichkeit, es zu definieren:

Null ist gerade.
Die Einheit ist seltsam.
Jede Zahl N hat die gleiche Parität wie N-2.

Schreiben Sie eine rekursive Funktion isEven gemäß diesen Regeln. Es muss eine Zahl akzeptieren und einen booleschen Wert zurückgeben.

Testen Sie es bei 50 und 75. Versuchen Sie es mit -1. Warum verhält sie sich so? Kann man das irgendwie beheben?

Testen Sie es bei 50 und 75. Sehen Sie, wie es sich bei -1 verhält. Warum? Können Sie sich eine Möglichkeit vorstellen, dies zu beheben?

Console.log(isEven(50)); // → true console.log(isEven(75)); // → false console.log(isEven(-1)); // → ??

Die Bohnen zählen.

Die Zeichennummer N einer Zeichenfolge kann durch Hinzufügen von .charAt(N) („string“.charAt(5)) ermittelt werden – ähnlich wie die Länge einer Zeichenfolge mithilfe von .length ermittelt wird. Der Rückgabewert ist eine Zeichenfolge, die aus einem Zeichen besteht (z. B. „k“). Das erste Zeichen einer Zeichenfolge hat die Position 0, was bedeutet, dass das letzte Zeichen die Position string.length - 1 hat. Mit anderen Worten, eine Zeichenfolge aus zwei Zeichen hat die Länge 2 und ihre Zeichenpositionen sind 0 und 1.

Schreiben Sie eine Funktion countBs, die eine Zeichenfolge als Argument verwendet und die Anzahl der in der Zeichenfolge enthaltenen „B“-Zeichen zurückgibt.

Schreiben Sie dann eine Funktion namens countChar, die in etwa wie countBs funktioniert, aber einen zweiten Parameter akzeptiert – das Zeichen, nach dem wir in der Zeichenfolge suchen (anstatt nur die Anzahl der „B“-Zeichen zu zählen). Überarbeiten Sie dazu die countBs-Funktion.



Freunden erzählen