Ausdrücke mit Bedingungs- und Zuweisungsoperator

7

Dieser Javascript-Ausdruck funktioniert in allen Browsern einwandfrei ( jsfiddle ):

%Vor%

Es wird zu 2 ausgewertet.

Aber warum? Ich würde hier eine Ausnahme erwarten, da die linke Seite der Zuweisung false ? 1 : x ist, was keine gültige Referenz ist. Vergleichen Sie mit ( jsfiddle ):

%Vor%

Dieser wirft einen ReferenceError . Ich überprüfte die JavaScript-Operator-Vorrang-Tabelle doppelt, es besagt, dass die Bedingung Operator ? : hat eine höhere Priorität als der Zuweisungsoperator = , also sollten beide Ausdrücke identisch sein, zumindest ich auch.

In Java, das ziemlich ähnliche Syntax- und Operator-Vorrangregeln wie Javascript hat, führen beide obigen Ausdrücke zu einem Fehler bei der Kompilierung, was durchaus sinnvoll ist.

Kann jemand diesen Unterschied erklären?

    
GOTO 0 01.06.2013, 11:42
quelle

4 Antworten

9

Hier sind die zwei Schlüssel zum Verständnis des Unterschieds zwischen dem bedingten JavaScript-Ausdruck und dem bedingten Java-Ausdruck:

Bitte lesen Sie den Hinweis am Ende dieses Abschnitts der ECMAScript 5-Anmerkung:

Ссылка

Lesen Sie jetzt den Java-Spezifikationsabschnitt für den bedingten Ausdruck:

Ссылка

Sie werden feststellen, dass der dritte Operand im ternären Operator in Java , wie in der ECMAScript 5-Notiz angegeben, nicht irgendein alter Ausdruck sein kann - er kann nur ein Bedingter Ausdruck sein. Für ECMAScript 5 kann der dritte Operand jedoch ein AssignmentExpression sein.

Wenn wir uns die Java-Spezifikation ansehen, sehen wir, dass Expression ein beliebiger Zuweisungsausdruck ist:

Ссылка

Aber ConditionalExpression ist entweder der ConditionalExpression mit dem ternären Operator (...? ...: ...) oder nur ein ConditionalOrExpression (in ES5 als LogicalOrExpression bezeichnet) (siehe die beiden ersten Links oben für diese Information). Die "Kette" dessen, was der ConditionalOrExpression sein kann, beginnt hier in Java:

Ссылка

Und hier in ECMAScript 5:

Ссылка

Nach der "Kette" von Ausdruckstypen rückwärts in der ECMAScript 5-Spezifikation (weil es einfacher zu folgen ist als die Java-Spezifikation) von der Bedingungsausdruck durchgehend bis zu jedem anderen Ausdruck, aber der Zuweisungsausdruck landet uns schließlich am Anfang - Primär Ausdruck:

Ссылка

Der zweite Operand in beiden obigen Code-Snippets ist ein primärer Ausdruck:

%Vor%

Das Ergebnis dieser ganzen Rigamarole (wenn ich richtig liege) ist, dass in Java der dritte Operand des ternären Operators keine Zuweisung sein kann, aber in JavaScript kann er das. Deshalb schlagen beide Beispiele in Java fehl, aber nur die zweite in JavaScript.

Warum funktioniert die erste in JavaScript, aber nicht die zweite?

%Vor%

funktioniert wie der folgende IIFE -Code (nicht tatsächlich , aber der folgende Code ist zur Veranschaulichung von wie das oben genannte funktioniert:

%Vor%

Also:

%Vor%

wird (wiederum nicht eigentlich - der folgende Code ist , der den obigen Code veranschaulicht):

%Vor%

Wenn Sie jedoch die Parens verwenden, trennen Sie in Ihrem zweiten Snippet explizit den bedingten Ausdruck von '= 2;':

%Vor%

wird (wiederum nicht eigentlich - der folgende Code ist , der den obigen Code veranschaulicht):

%Vor%

Das Verhalten des ternären Operators "verhält sich wie das Verhalten der Beispiel-IIFE-Funktion" gibt jedes beliebige x zurück und ist ein Wert , keine Referenz, die nicht zugewiesen werden kann. Daher der Fehler. Dies wäre wie der folgende Code (wenn x === 3):

%Vor%

Offensichtlich kann man das nicht tun.

In Java glaube ich, dass der erste einen Fehler verursacht, weil der dritte Operator keine Zuweisung sein kann, der zweite einen Fehler ergibt, weil Sie keinen Wert zuweisen können (genau wie in JavaScript).

Soweit es die Rangfolge des Operators betrifft, sehen Sie sich bitte folgenden Code an:

%Vor%

Die ersten beiden sind leicht zu verstehen, wenn man sie im obigen illustrativen Code des IIFE betrachtet.

In der ersten Zeile wird x ausgewertet und der bedingte Ausdruck wird mit 3 bewertet - das ist einfach.

In der zweiten Zeile kann ich den besten Weg beschreiben, dass der Bedingungsoperator (? :) bewirkt, dass sogar der Operator mit der niedrigeren Priorität '=' als vollständiger Ausdruck ausgewertet wird, nicht weil (? :) eine höhere Priorität hat. aber da die Spezifikation angibt, dass der Zuweisungsausdruck nach dem ':' ausgewertet wird (einschließlich des '= 2'-Teils), wird er als AssignmentExpression ausgewertet. Dieses Verhalten wird in den obigen IIFE-Beispielen in der return-Anweisung deutlicher. Mit mindestens JavaScript können Sie eine Zuweisung nicht nur im zweiten Operanden, sondern auch im dritten des bedingten Ausdrucks haben.

In der dritten Zeile wird jedoch bereits ein vollständiger Zuweisungsausdruck im Ausdruck "x = 2" gefunden, und der ternäre Operator verwendet ihn als vollständigen dritten Operanden, und der Operator "," hat einen niedrigeren Vorrang als jeder andere , erhalten wir das Äquivalent zum folgenden Code:

%Vor%

In der vierten Codezeile kapselt der gesamte Ausdruck innerhalb der console.log () -Anweisung in parens das ', 4' in den ternären Ausdruck ':' als Teil des dritten Operanden.

Die folgenden Beispiele zeigen die obige Diskussion mit Live-Code.Beachten Sie, dass die ersten zwei den gleichen Fehler haben, nachdem Sie zweimal '2' gedruckt haben:

FIDDLE1

FIDDLE2

FIDDLE3

    
Aeoril 09.10.2013, 02:17
quelle
14

Wie Sie bei MDN gefunden haben, hat ? : eine höhere Präzedenz als der Zuweisungsoperator = , was bedeutet, dass JS Ihre Anweisung wie folgt liest:

%Vor%

Auf den ersten Blick mag das rückwärts scheinen, aber was es bedeutet, dass ? : drei Operanden erwartet, wobei der Teil rechts von : der dritte Operand ist. Da = eine niedrigere Priorität hat, wird x = 2 zum dritten Operanden.

Die Warnung zeigt 2 an, weil die Zuweisung x = 2 die x -Variable auf 2 setzt und dann dieser (Unter) -Ausdruck zu 2 .

ausgewertet wird

Ihre zweite Version:

%Vor%

... gibt einen Referenzfehler, da zuerst der (false ? 1 : x) -Teil ausgewertet wird, der den -Wert auswertet, der mit x ( undefined ) verknüpft ist, er gibt die Variable% nicht zurück co_de% selbst x funktioniert nicht.

    
nnnnnn 01.06.2013 11:46
quelle
5

Der ternäre Operator (?) benötigt drei Werte: Eine Bedingung , eine if-true und eine if-false .

Im Ausdruck

%Vor%

Der Compiler sieht false als Bedingung, 1 als if-true und x = 2 . Schon seit ? hat Vorrang vor = das x = 2 wurde noch nicht ausgewertet. Da false von Natur aus falsch ist, ist x = 2 das, was zurückgegeben wird.

Bei der Auswertung x = 2 wird 2 zurückgegeben.

Daher können Sie

schreiben %Vor%

In diesem Beispiel sind x und y beide auf 2 gesetzt.

Der Grund, warum das ganze x = 2 als if-false Operand angesehen wird und nicht nur das x ist, weil der ternäre Operator nimmt alles auf der rechten Seite: als if-false , wenn es innerhalb des Bereichs liegt.

Wenn Sie jedoch die eckigen Klammern verwenden, setzen Sie ein Literal (was auch immer x ist) auf 2, was zu einem Fehler führt.

Ich kann die Frage nicht beantworten, warum es in Javascript funktioniert, während es in Java jedoch zu einem Fehler kommt. Ich kann nur leicht abweichende Betreiberprioritäten annehmen?

    
Ryxuma 06.10.2013 18:41
quelle
0

Ich würde nicht so programmieren, aber die Tatsache, dass es funktioniert, ist für mich offensichtlich:

Der Start von mit Ihrer Aussage ?: hat eine höhere Priorität als = - das ist falsch, da ?: 15 hat, während = 17 hat.
Daher ist der erste Code ähnlich false ? 1 : (x = 2); - von da an ist es ziemlich klar, was meiner Meinung nach passiert, das ist ähnlich if (false) 1; else x=2;

Ihr zweites Code-Snippet kann nicht funktionieren, weil die linke Seite von =% undefined ist und Sie nichts zu undefined zuweisen können, wie es bei ReferenceError der Fall ist.

    
luk2302 01.06.2013 11:57
quelle