Vorrang des Operators beim ternären Javascript-Operator


116

Ich kann meinen Kopf nicht um den ersten Teil dieses Codes (+ =) in Kombination mit dem ternären Operator wickeln.

h.className += h.className ? ' error' : 'error'

Ich denke, dieser Code funktioniert wie folgt:

h.className = h.className + h.className ? ' error' : 'error'

Das ist aber nicht richtig, da dies zu einem Fehler in meiner Konsole führt.

Meine Frage ist also, wie ich diesen Code richtig interpretieren soll.

Antworten:


141
h.className = h.className + (h.className ? ' error' : 'error')

Sie möchten, dass der Bediener arbeitet h.className, genauer gesagt.
Natürlich sollte kein Schaden entstehen h.className += ' error', aber das ist eine andere Sache.

Beachten Sie außerdem, dass +der ternäre Operator Vorrang hat: Vorrang des JavaScript-Operators


3
Ich denke, es sollte beachtet werden, dass, obwohl kein Schaden entstehen könnte h.className += ' error', es auch ein Leerzeichen am Anfang der Zeichenfolge hinterlässt, wenn es anfangs leer war. Ich glaube, der Sinn der ternären Operation besteht darin, eine sauber aussehende Saite zu erzeugen.
JMTyler

@JMTyler - Genau das habe ich angedeutet - Wenn alles nur getan wird, um von Anfang an einen Platz zu behalten, ist ich es nicht wert. (Randfall enthält exakte jQuery- oder XPath-Selektoren). Trotzdem danke.
Kobi

@Kobi +1 nur für die Vorrangwarnung des Bedieners!
Ed Chapel

129

Denk darüber so:

<variable> = <expression> ? <true clause> : <false clause>

Die Art und Weise, wie die Anweisung ausgeführt wird, ist im Wesentlichen wie folgt:

  1. Wird <expression>als wahr oder als falsch bewertet?
  2. Wenn <expression>der Wert true ergibt, wird der Wert von <true clause>zugewiesen <variable>, <false clause>ignoriert und die nächste Anweisung ausgeführt.
  3. Wenn der Wert <expression>false <true clause>ergibt , wird er ignoriert und der Wert von <false clause>wird zugewiesen <variable>.

Mit dem ternären Operator in dieser und anderen Sprachen ist es wichtig zu erkennen, dass jeder Code, in dem er enthalten <expression>ist, bei der Auswertung ein boolesches Ergebnis liefert: entweder wahr oder falsch.

Im Fall Ihres Beispiels ersetzen Sie "zugewiesen zu" in meiner Erklärung durch "hinzugefügt zu" oder ähnlich für die von Ihnen verwendete Kurzschriftarithmetik, falls vorhanden.


Beachten Sie sicher, ob der perfekte Kommentar angemessen ist :) Es wird jede Erklärung übersprungen, warum die linken Ausdrücke zuerst "gruppiert" werden (dh weil sie +eine höhere Priorität haben als der bedingte / ternäre Operator (tatsächlich ist der bedingte Operator fast immer der letzte) ausgewertet in einem beliebigen Ausdruck).
Gone Coding

10

Das +=macht, was Sie wollen, aber in der ternären Aussage auf der rechten Seite prüft es, ob h.classNamees sich um Falsey handelt, was es wäre, wenn es undefiniert wäre. Wenn es wahr ist (dh wenn bereits ein Klassenname angegeben ist), wird ein Fehler mit einem Leerzeichen hinzugefügt (dh wenn eine neue Klasse hinzugefügt wird), andernfalls wird es ohne Leerzeichen hinzugefügt.

Der Code könnte wie vorgeschlagen umgeschrieben werden, Sie müssen jedoch angeben, dass h.classNameer für den Vergleich der Wahrhaftigkeit und nicht für die Verwendung seines tatsächlichen Werts im ternären Operator verwendet werden soll. Achten Sie also darauf, dass Sie sich nicht um die Verkettung von Werten kümmern gleichzeitig mit Ihrer ternären Operation:

h.className = h.className + (h.className ? ' error' : 'error');

13
Nun ja, undefinedist nicht falsch, es wird nur so behandelt, als wäre es
David Hedlund

4

Die rechte Seite des =Bedieners wird von links nach rechts ausgewertet. So,

g.className = h.className + h.className ? ' error' : 'error';`

ist äquivalent zu

h.className = (h.className + h.className) ? ' error' : 'error';

Äquivalent zu sein

h.className += h.className ? ' error' : 'error';

Sie müssen die ternäre Anweisung in Klammern trennen

h.className = h.className + (h.className ? ' error' : 'error');

3
if (h.className) {
    h.className = h.className + ' error';
} else {
    h.className = h.className + 'error';
}

sollte gleichbedeutend sein mit:

h.className += h.className ? ' error' : 'error';

1

Ich weiß, dass dies eine sehr alte Frage ist, aber ich bin mit keiner der Antworten 100% zufrieden, da sie alle unvollständig erscheinen. Also los geht's wieder von den ersten Prinzipien:

Das übergeordnete Ziel des Benutzers:

Zusammenfassend: "Ich möchte erroreiner Zeichenfolge einen Klassennamen hinzufügen , optional mit einem führenden Leerzeichen, wenn die Zeichenfolge bereits Klassennamen enthält."

Einfachste Lösung

Wie Kobi vor 5 Jahren betonte, verursacht ein führender Platz in Klassennamen keine Probleme mit bekannten Browsern. Die kürzeste richtige Lösung wäre also tatsächlich:

h.className += ' error';

Das hätte die eigentliche Antwort auf das eigentliche Problem sein sollen .


Wie dem auch sei, die gestellten Fragen waren ...

1) Warum hat das funktioniert?

h.className += h.className ? ' error' : 'error'

Der bedingte / ternäre Operator funktioniert wie eine if-Anweisung, die das Ergebnis seiner trueoder seiner falsePfade einer Variablen zuweist .

Dieser Code hat also funktioniert, weil er einfach wie folgt ausgewertet wird:

if (h.className IS NOT null AND IS NOT undefined AND IS NOT '') 
    h.className += ' error'
else
    h.className += 'error'

2) und warum ist das kaputt gegangen?

h.className = h.className + h.className ? ' error' : 'error'

Die Frage lautet "das gibt einen [n] Fehler in meiner Konsole", was Sie irreführen könnte, zu glauben, dass der Code nicht funktioniert . In der Tat ist der folgende Code ausgeführt werden , ohne Fehler , aber es gibt einfach ‚Fehler‘ , wenn die Zeichenfolge nicht war leer und ‚Fehler‘ , wenn die Zeichenfolge war leer und so nicht den Anforderungen entsprechen .

Dieser Code führt immer zu einer Zeichenfolge, die nur enthält ' error'oder 'error'weil er diesen Pseudocode auswertet:

if ((h.className + h.className) IS NOT null AND IS NOT undefined AND IS NOT '')
    h.className = ' error'
else
    h.className = 'error'

Der Grund dafür ist, dass der Additionsoperator ( +für das allgemeine Volk) eine höhere "Priorität" (6) hat als der bedingte / ternäre Operator (15). Ich weiß, dass die Zahlen rückwärts erscheinen

Vorrang bedeutet einfach, dass jeder Operatortyp in einer Sprache in einer bestimmten vordefinierten Reihenfolge (und nicht nur von links nach rechts) ausgewertet wird.

Referenz: Vorrang für Javascript-Operatoren

So ändern Sie die Reihenfolge der Bewertung:

Jetzt wissen wir, warum es fehlschlägt. Sie müssen wissen, wie es funktioniert.

Einige andere Antworten sprechen davon , die Priorität zu ändern , aber Sie können nicht . Der Vorrang ist fest mit der Sprache verbunden. Das ist nur ein festes Regelwerk ... Sie können jedoch die Reihenfolge der Auswertung ändern ...

Das Tool in unserer Toolbox, das die Reihenfolge der Auswertung ändern kann , ist der Gruppierungsoperator (auch als Klammern bezeichnet). Dazu wird sichergestellt, dass die Ausdrücke in den Klammern vor Operationen außerhalb der Klammern ausgewertet werden . Das ist alles was sie tun, aber das ist genug.

Klammern funktionieren einfach, weil sie (Gruppierungsoperatoren) eine höhere Priorität haben als alle anderen Operatoren ("es gibt jetzt eine Stufe 0").

Durch einfaches Hinzufügen von Klammern ändern Sie die Reihenfolge der Auswertung, um sicherzustellen, dass der bedingte Test zuerst durchgeführt wird, bevor die einfache Verkettung von Zeichenfolgen erfolgt:

h.className = h.className + (h.className ? ' error' : 'error')

Ich werde diese Antwort jetzt ungesehen unter den anderen rosten lassen :)


1

Ich möchte eine Erklärung für Wayne auswählen:

<variable> = <expression> ? <true clause> : <false clause>

Betrachten wir beide Fälle:

case 1:
h.className += h.className ? 'true' : 'false'     
  • Der Zuweisungsoperator funktioniert einwandfrei und der Wert wird angehängt
  • Wenn es zum ersten Mal ausgeführt wird, ist o / p: false
  • 2. Mal. o / p: falsetrue - Werte werden weiterhin angehängt

case2: h.className = h.className + h.className? 'wahr falsch'

  • Das Ergebnis ist nicht dasselbe wie in Fall 1
  • Wenn es zum ersten Mal ausgeführt wird, ist o / p: false
  • 2. Mal. o / p: false - Werte werden nicht ständig angehängt

explanation

Im obigen Code funktioniert Fall 1 einwandfrei

in der Erwägung, dass Fall 2:

h.className = h.className + h.className ? 'true' : 'false'
is executed as 
 h.className = (h.className + h.className) ? 'true' : 'false'

h.className + h.className=> wird als Ausdruck für ternären Operator betrachtet, da ternärer Operator eine höhere Priorität hat. Daher wird immer nur das Ergebnis des ternären Ausdrucks zugewiesen

Sie müssen die Priorität mithilfe von Klammern definieren

Sie müssen die Reihenfolge der Bewertung definieren, die mithilfe von Klammern berücksichtigt werden soll, damit Fall 2 als Fall 1 funktioniert

h.className = h.className + (h.className ? ' error' : 'error') 

1
Die Terminologie hier ist nicht ganz richtig. Die Sprache hat Vorrang, Sie definieren sie nicht . Sie definieren stattdessen die Reihenfolge der Auswertung, indem Sie Klammern einfügen (die eine höhere Priorität haben als alle anderen Operatoren).
Gone Coding

@TrueBlueAussie Ich akzeptiere es. Ich schätze für Ihre Absicht, +1
Angelin Nadar
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.