JavaScript – Das Handbuch für die Praxis. David Flanagan

JavaScript  –  Das Handbuch für die Praxis - David Flanagan


Скачать книгу
welche Funktionen eval() aufrufen, und deshalb nicht mehr aggressiv optimieren. Dieses Problem hätte man vermeiden können, wäre eval() tatsächlich ein Operator (und ein reserviertes Wort). Wir werden weiter unten (in 4.12.2 und 4.12.3) die Einschränkungen kennenlernen, denen man eval() unterworfen hat, damit es eher einem Operator ähnelt.

       4.12.1eval()

      eval() erwartet ein Argument. Übergeben Sie einen anderen Wert als einen String, liefert es einfach diesen Wert zurück. Ansonsten versucht es, den übergebenen String als JavaScript-Code zu parsen, und löst einen SyntaxError aus, falls dieser Versuch scheitert. Kann es den String erfolgreich parsen, wertet es den Code aus und liefert den Wert des letzten Ausdrucks oder der letzten Anweisung im String zurück oder aber undefined, wenn der letzte Ausdruck bzw. die letzte Anweisung keinen Wert hat. Löst die ausgewertete Zeichenkette eine Ausnahme aus, wird diese Ausnahme an eval() weitergereicht.

      Wird eval() auf diese Weise eingesetzt (und das ist hier wesentlich), nutzt es die Variablenumgebung des Codes, aus dem es aufgerufen wird. Damit liest die Funktion Werte von Variablen auf gleiche Weise aus und definiert neue Variablen und Funktionen auf gleiche Weise wie der lokale Umgebungscode. Definiert eine Funktion eine lokale Variable x und ruft dann eval("x") auf, erhält sie den Wert der lokalen Variablen. Ruft sie eval("x=1") auf, ändert sie den Wert der lokalen Variablen. Und wenn die Funktion eval("var y = 3;") aufruft, deklariert sie eine neue lokale Variable y. Wird in der auszuwertenden Zeichenkette dagegen let oder const verwendet, gilt die deklarierte Variable oder Konstante nur lokal innerhalb von eval() (d.h. innerhalb der Auswertung) und wird nicht in der aufrufenden Umgebung definiert.

      In ähnlicher Weise kann eine Funktion beispielsweise eine lokale Funktion deklarieren:

      eval("function f() { return x+1; }");

      Rufen Sie eval() aus Code der höchsten Programmebene auf, operiert es natürlich auf globalen Variablen und globalen Funktionen.

      Beachten Sie bitte, dass der Codestring, den Sie an eval() übergeben, syntaktisch für sich stehend sinnvoll sein muss. Sie können eval() nicht nutzen, um Codefragmente in eine Funktion einzubringen. Beispielsweise ist der Ausdruck eval("return;") sinnlos, weil return nur in Funktionen erlaubt ist und der Umstand, dass der ausgewertete String die gleiche Variablenumgebung nutzt wie die aufrufende Funktion, den String nicht zu einem Teil der Funktion macht. Wäre Ihr String ein eigenständiges Skript (und sei es nur ein ganz kurzes wie x=0), dürfte er an eval() übergeben werden. Andernfalls löst eval() einen SyntaxError aus.

       4.12.2Globales eval()

      eval() ist für den JavaScript-Optimierer deshalb so problematisch, weil es lokale Variablen ändern kann. Um das zu umgehen, führen Interpreter bei Funktionen, die eval() aufrufen, einfach weniger Optimierungen aus. Aber was soll ein JavaScript-Interpreter tun, wenn ein Skript ein Alias für eval() definiert und die Funktion einfach unter einem anderen Namen aufruft? Die JavaScript-Spezifikation sieht vor, dass bei einem Aufruf von eval() unter einem anderen Namen die Zeichenkette so ausgewertet werden soll, als würde es sich um globalen Code der höchsten Programmebene handeln. Der ausgewertete Code darf neue globale Variablen oder Funktionen deklarieren und globale Variablen erstellen, darf aber in der aufrufenden Funktion keine Variablen mehr nutzen oder verändern und kommt so den lokalen Optimierungen nicht mehr ins Gehege.

      Ein »direktes Eval« ist ein Aufruf der eval()-Funktion mit einem Ausdruck, der den genauen, nicht qualifizierten Namen »eval« verwendet (der damit immer mehr wie ein reserviertes Wort wirkt). Direkte Aufrufe von eval() nutzen die Variablenumgebung des aufrufenden Kontexts. Jeder andere – indirekte – Aufruf nutzt als Variablenumgebung das globale Objekt und kann lokale Variablen oder Funktionen weder lesen noch schreiben noch definieren. (Sowohl direkte als auch indirekte Aufrufe können neue Variablen nur mit var definieren. Die Verwendung von let und const innerhalb einer auszuwertenden Zeichenkette erzeugt Variablen und Konstanten, die lokal zur Auswertung gehören und die aufrufende oder globale Umgebung nicht verändern.)

      Der folgende Code verdeutlicht dies:

      const geval = eval; // Die Verwendung eines anderen Namens führt zu

      // einem globalen Eval.

      let x = "global", y = "global"; // Zwei globale Variablen.

      function f() { // Diese Funktion führt ein lokales Eval aus.

      let x = "local"; // Eine lokale Variable definieren.

      eval("x += 'changed';"); // Das direkte Eval setzt die lokale Variable.

      return x; // Den geänderten lokalen Wert zurückliefern.

      }

      function g() { // Diese Funktion führt ein globales Eval aus.

      let y = "local"; // Eine lokale Variable.

      geval("y += 'changed';"); // Ein indirektes Eval setzt die globale

      // Variable.

      return y; // Liefert den unveränderten lokalen Wert.

      }

      console.log(f(), x); // Lokale Variable geändert: ergibt "localchanged global".

      console.log(g(), y); // Globale Variable geändert: ergibt "local globalchanged".

      Die Möglichkeit, ein globales Eval durchzuführen, ist übrigens mehr als eine Anpassung an die Anforderungen des Optimierers. Das globale Eval ist tatsächlich eine unglaublich nützliche Einrichtung, mit der man Strings mit Code ausführen kann, als enthielten sie unabhängige Skripte der obersten Ebene. Wie bereits zu Anfang dieses Abschnitts erwähnt, kommt es nur äußerst selten vor, dass man Strings mit Code auswerten muss. Wenn Sie aber das Gefühl haben, es sei notwendig, ist meist ein globales Eval die bessere Lösung als ein lokales.

       4.12.3eval() im strict-Modus

      Der strict-Modus (siehe 5.6.3) unterwirft das Verhalten der Funktion eval() und sogar die Verwendung des Identifiers »eval« weiteren Einschränkungen. Wird eval() aus Code aufgerufen, der im strict-Modus ausgeführt wird, oder beginnt der auszuwertende Code selbst mit der Direktive "use strict", führt eval() ein lokales Eval mit einer privaten Variablenumgebung aus. Das bedeutet, dass im strict-Modus evaluierter Code lokale Variablen abfragen und setzen, aber keine neuen Variablen oder Funktionen im lokalen Bereich definieren kann.

      Außerdem gleicht der strict-Modus eval() einem Operator noch stärker an, indem er »eval« praktisch zu einem reservierten Wort umfunktioniert. Es ist nicht erlaubt, die eval()-Funktion mit einem neuen Wert zu überschreiben. Und es ist nicht erlaubt, eine Variable, eine Funktion, einen Funktionsparameter oder einen Parameter eines catch-Blocks mit dem Namen »eval« zu deklarieren.

       4.13Weitere Operatoren

      JavaScript unterstützt eine Reihe weiterer Operatoren mit unterschiedlichen Aufgaben, die in den folgenden Abschnitten beschrieben werden.

       4.13.1Der Bedingungsoperator (?:)

      Der Bedingungsoperator ist der einzige Ternäroperator – also ein Operator, der mit drei Operanden arbeitet – in JavaScript und wird in der Tat gelegentlich einfach als »der Ternäroperator« bezeichnet. Dieser Operator wird auch oft in der Form ?: geschrieben, obwohl er im Code nicht ganz in dieser Form erscheint. Weil dieser Operator drei Operanden hat, steht der erste vor dem ?, der zweite zwischen ? und : und der dritte nach dem :. Er wird wie folgt verwendet:

      x


Скачать книгу