Get to know MDN better
Dieser Inhalt wurde automatisch aus dem Englischen übersetzt, und kann Fehler enthalten. Erfahre mehr über dieses Experiment.
Operatorpräzedenz bestimmt, wie Operatoren im Verhältnis zueinander geparst werden. Operatoren mit höherer Präzedenz werden zu Operanden von Operatoren mit niedrigerer Präzedenz.
Betrachten Sie einen Ausdruck, der durch die folgende Darstellung beschreibbar ist, wobei sowohl OP1 als auch OP2 Platzhalter für Operatoren sind.
a OP1 b OP2 cDas obige Diagramm hat zwei mögliche Interpretationen:
(a OP1 b) OP2 c a OP1 (b OP2 c)Welche Interpretation die Sprache annimmt, hängt von der Identität von OP1 und OP2 ab.
Wenn OP1 und OP2 unterschiedliche Präzedenzstufen haben (siehe Tabelle unten), wird der Operator mit der höheren Präzedenz zuerst ausgeführt, und die Assoziativität spielt keine Rolle. Beachten Sie, dass die Multiplikation eine höhere Präzedenz als die Addition hat und zuerst ausgeführt wird, auch wenn die Addition zuerst im Code geschrieben ist.
Innerhalb von Operatoren mit derselben Präzedenz werden sie von der Sprache nach Assoziativität gruppiert. Linksassoziativität (von links nach rechts) bedeutet, dass sie interpretiert wird als (a OP1 b) OP2 c, während Rechtsassoziativität (von rechts nach links) bedeutet, dass sie interpretiert wird als a OP1 (b OP2 c). Zuweisungsoperatoren sind rechtsassoziativ, so dass Sie schreiben können:
mit dem erwarteten Ergebnis, dass a und b den Wert 5 erhalten. Dies liegt daran, dass der Zuweisungsoperator den Wert zurückgibt, der zugewiesen wird. Zuerst wird b auf 5 gesetzt. Dann wird a ebenfalls auf 5 gesetzt – der Rückgabewert von b = 5, also der rechte Operand der Zuweisung.
Als weiteres Beispiel hat der einzigartige Exponentialoperator eine Rechtsassoziativität, während andere arithmetische Operatoren eine Linksassoziativität haben.
Operatoren werden zuerst nach Präzedenz gruppiert, und dann für benachbarte Operatoren mit derselben Präzedenz nach Assoziativität. Beim Mischen von Division und Exponentialrechnung kommt die Exponentialrechnung immer vor der Division. Zum Beispiel ergibt 2 ** 3 / 3 ** 2 0.8888888888888888, weil es dasselbe ist wie (2 ** 3) / (3 ** 2).
Für unäre Präfixoperatoren, nehmen wir folgendes Muster an:
OP1 a OP2 bwo OP1 ein unärer Präfixoperator und OP2 ein binärer Operator ist. Wenn OP1 eine höhere Präzedenz als OP2 hat, wird es als (OP1 a) OP2 b gruppiert; andernfalls wäre es OP1 (a OP2 b).
Wenn der unäre Operator auf dem zweiten Operanden liegt:
a OP2 OP1 bDann muss der binäre Operator OP2 eine niedrigere Präzedenz als der unäre Operator OP1 haben, damit es als a OP2 (OP1 b) gruppiert wird. Zum Beispiel ist das Folgende ungültig:
Da + eine höhere Präzedenz als yield hat, würde dies zu (a + yield) 1 — aber da yield ein reserviertes Wort in Generatorfunktionen ist, wäre dies ein Syntaxfehler. Zum Glück haben die meisten unären Operatoren eine höhere Präzedenz als binäre Operatoren und leiden nicht unter diesem Problem.
Haben wir zwei unäre Präfixoperatoren:
OP1 OP2 aDann muss der unäre Operator, der näher am Operanden liegt, OP2, eine höhere Präzedenz als OP1 haben, damit es als OP1 (OP2 a) gruppiert wird. Es ist möglich, es andersherum zu haben und mit (OP1 OP2) a zu enden:
Weil await eine höhere Präzedenz als yield, wird dies zu (await yield) 1, was bedeutet, dass auf einen Identifikator namens yield gewartet wird, und ein Syntaxfehler. Ähnlich, wenn Sie new !A; haben, weil ! eine niedrigere Präzedenz als new hat, wird dies zu (new !) A, was offensichtlich ungültig ist. (Dieser Code sieht sowieso unsinnig aus, da !A immer ein Boolean, keine Konstruktorfunktion ergibt.)
Für unäre Postfixoperatoren (nämlich ++ und --) gelten die gleichen Regeln. Zum Glück haben beide Operatoren eine höhere Präzedenz als jeder binäre Operator, sodass die Gruppierung immer so ist, wie man es erwarten würde. Außerdem, da ++ auf einen Wert und nicht auf eine Referenz evaluiert wird, können Sie nicht mehrere Inkremente miteinander verkettet schreiben.
Die Operatorpräzedenz wird rekursiv behandelt. Betrachten Sie zum Beispiel diesen Ausdruck:
Zuerst gruppieren wir Operatoren mit unterschiedlicher Präzedenz nach absteigenden Präzedenzstufen.
Innerhalb der *//-Gruppe, weil sie linksassoziativ sind, wird der linke Operand gruppiert.
Beachten Sie, dass Operatorpräzedenz und Assoziativität nur die Reihenfolge der Auswertung von Operatoren beeinflussen (die implizite Gruppierung), nicht aber die Auswertungsreihenfolge der Operanden. Die Operanden werden immer von links nach rechts ausgewertet. Die höherstufigen Präzedenz-Ausdrücke werden immer zuerst evaluiert, und ihre Ergebnisse werden dann gemäß der Reihenfolge der Operatorpräzedenz zusammengesetzt.
Wenn Sie mit binären Bäumen vertraut sind, denken Sie daran wie bei einer Post-Order-Traversierung.
/ ┌────────┴────────┐ echo("left", 4) ** ┌────────┴────────┐ echo("middle", 3) echo("right", 2)Nachdem alle Operatoren ordnungsgemäß gruppiert sind, bilden die binären Operatoren einen Binärbaum. Die Auswertung beginnt mit der äußersten Gruppe — die der Operator mit der niedrigsten Präzedenz ist (in diesem Fall /). Der linke Operand dieses Operators wird zuerst ausgewertet, der möglicherweise aus höherstufigen Präzedenz-Operatoren besteht (wie ein Aufrufausdruck in echo("left", 4)). Nachdem der linke Operand ausgewertet wurde, wird der rechte Operand auf die gleiche Weise ausgewertet. Daher werden alle Blattknoten — die echo()-Aufrufe — von links nach rechts besucht, unabhängig von der Präzedenz der Operatoren, die sie verbinden.
Im vorherigen Abschnitt sagten wir: "die höherstufigen Präzedenz-Ausdrücke werden immer zuerst ausgewertet" — das ist im Allgemeinen wahr, muss jedoch mit der Anerkennung des Kurzschlusses ergänzt werden, bei dem ein Operand möglicherweise überhaupt nicht ausgewertet wird.
Kurzschluss ist Fachjargon für bedingte Auswertung. Zum Beispiel, im Ausdruck a && (b + c), wenn a falsy ist, wird der Teilausdruck (b + c) gar nicht ausgewertet, selbst wenn er gruppiert ist und daher eine höhere Präzedenz als && hat. Man könnte sagen, dass der logische Und-Operator (&&) "kurzgeschlossen" ist. Zusammen mit logischem Und sind andere kurzgeschlossene Operatoren logisches Oder (||), "nullish coalescing" (??) und optionales Verkettung (?.).
Bei der Auswertung eines kurzgeschlossenen Operators wird immer der linke Operand ausgewertet. Der rechte Operand wird nur ausgewertet, wenn der linke Operand das Ergebnis der Operation nicht bestimmen kann.
Hinweis: Das Verhalten des Kurzschlusses ist in diesen Operatoren eingebaut. Andere Operatoren würden immer beide Operanden auswerten, unabhängig davon, ob dies tatsächlich nützlich ist — zum Beispiel wird NaN * foo() immer foo aufrufen, selbst wenn das Ergebnis nie etwas anderes als NaN wäre.
Das vorherige Modell einer Post-Order-Traversierung bleibt bestehen. Allerdings entscheidet die Sprache, nachdem der linke Unterbaum eines kurzgeschlossenen Operators besucht wurde, ob der rechte Operand ausgewertet werden muss. Wenn nicht (zum Beispiel, weil der linke Operand von || bereits truthy ist), wird das Ergebnis direkt zurückgegeben, ohne den rechten Unterbaum zu besuchen.
Betrachten Sie diesen Fall:
Nur C() wird ausgewertet, trotz dass && eine höhere Präzedenz hat. Das bedeutet nicht, dass || in diesem Fall eine höhere Präzedenz hat — es ist genau weil (B() && A()) eine höhere Präzedenz hat, dass dieser Ausdruck als Ganzes vernachlässigt wird. Wenn es umgestellt wird als:
Dann würde der Kurzschluss-Effekt von && lediglich verhindern, dass B() ausgewertet wird, aber da A() && B() als Ganzes false ist, würde C() trotzdem ausgewertet werden.
Beachten Sie jedoch, dass der Kurzschluss das Endergebnis der Auswertung nicht ändert. Es beeinflusst nur die Auswertung der Operanden, nicht wie Operatoren gruppiert werden — wenn die Auswertung der Operanden keine Nebeneffekte hat (zum Beispiel Protokollierung in der Konsole, Variablenzuweisungen, Fehler auslösen), wäre der Kurzschluss überhaupt nicht bemerkbar.
Die Zuweisungsgegenstücke dieser Operatoren (&&=, ||=, ??=) sind ebenfalls kurzgeschlossen. Sie sind so kurzgeschlossen, dass die Zuweisung überhaupt nicht stattfindet.
Die folgende Tabelle listet Operatoren in der Reihenfolge von der höchsten Präzedenz (18) zur niedrigsten Präzedenz (1) auf.
Einige allgemeine Anmerkungen zur Tabelle:
| 18: Gruppierung | k.A. | Gruppierung (x) |
[1] |
| 17: Zugriff und Aufruf | links-nach-rechts | Mitgliedszugriff x.y |
[2] |
| Optionale Verkettung x?.y |
|||
| k.A. |
Berechneter Mitgliedszugriff x[y] |
[3] | |
| new mit Argumenteliste new x(y) |
[4] | ||
|
Funktionsaufruf x(y) |
|||
| import(x) | |||
| 16: new | k.A. | new ohne Argumenteliste new x |
|
| 15: Postfix-Operatoren | k.A. |
Postfix-Inkrement x++ |
[5] |
|
Postfix-Dekrement x-- |
|||
| 14: Präfix-Operatoren | k.A. |
Präfix-Inkrement ++x |
[6] |
|
Präfix-Dekrement --x |
|||
|
Logisches NICHT !x |
|||
|
Bitweises NICHT ~x |
|||
|
Unäres Plus +x |
|||
|
Unäre Negation -x |
|||
| typeof x | |||
| void x | |||
| delete x | [7] | ||
| await x | |||
| 13: Exponentiation | rechts-nach-links |
Exponentiation x ** y |
[8] |
| 12: Multiplikative Operatoren | links-nach-rechts |
Multiplikation x * y |
|
|
Division x / y |
|||
|
Rest x % y |
|||
| 11: Additive Operatoren | links-nach-rechts |
Addition x + y |
|
|
Subtraktion x - y |
|||
| 10: Bitweises Verschieben | links-nach-rechts |
Linksschieben x << y |
|
|
Rechtsschieben x >> y |
|||
|
Ungar. Rechtsschieben x >>> y |
|||
| 9: Relationale Operatoren | links-nach-rechts |
Kleiner als x < y |
|
|
Kleiner gleich x <= y |
|||
|
Größer als x > y |
|||
|
Größer gleich x >= y |
|||
| x in y | |||
| x instanceof y | |||
| 8: Gleichheitsoperatoren | links-nach-rechts |
Gleichheit x == y |
|
|
Ungleichheit x != y |
|||
|
Strenge Gleichheit x === y |
|||
|
Strenge Ungleichheit x !== y |
|||
| 7: Bitweises UND | links-nach-rechts |
Bitweises UND x & y |
|
| 6: Bitweises XOR | links-nach-rechts |
Bitweises XOR x ^ y |
|
| 5: Bitweises ODER | links-nach-rechts |
Bitweises ODER x | y |
|
| 4: Logisches UND | links-nach-rechts |
Logisches UND x && y |
|
| 3: Logisches ODER, Nullish coalescing | links-nach-rechts |
Logisches ODER x || y |
|
|
Nullish coalescing Operator x ?? y |
[9] | ||
| 2: Zuweisung und Sonstiges | rechts-nach-links |
Zuweisung x = y |
[10] |
|
Additionszuweisung x += y |
|||
|
Subtraktionszuweisung x -= y |
|||
|
Exponentiationszuweisung x **= y |
|||
|
Multiplikationszuweisung x *= y |
|||
|
Divisionszuweisung x /= y |
|||
|
Restzuweisung x %= y |
|||
|
Linksverschiebungszuweisung x <<= y |
|||
|
Rechtsverschiebungszuweisung x >>= y |
|||
|
Ungar. Rechtsverschiebungszuweisung x >>>= y |
|||
|
Bitweises UND-Zuweisung x &= y |
|||
|
Bitweises XOR-Zuweisung x ^= y |
|||
|
Bitweises ODER-Zuweisung x |= y |
|||
|
Logisches UND-Zuweisung x &&= y |
|||
|
Logisches ODER-Zuweisung x ||= y |
|||
|
Nullish coalescing Zuweisung x ??= y |
|||
| rechts-nach-links |
Bedingungsoperator (ternär) x ? y : z |
[11] | |
| rechts-nach-links |
Arrow x => y |
[12] | |
| k.A. | yield x | ||
| yield* x | |||
|
Spread ...x |
[13] | ||
| 1: Komma | links-nach-rechts |
KommOperator x, y |
Bemerkungen:
Die Präzedenz der Gruppen 17 und 16 kann etwas zweideutig sein. Hier sind einige Beispiele zur Klärung.
Der Bauplan für ein besseres Internet.
Teile dieses Inhalts sind ©1998–2026 von einzelnen mozilla.org-Mitwirkenden. Inhalte sind verfügbar unter einer Creative-Commons-Lizenz.