37 votes

Pourquoi s'agit-il d'une affectation non valide à gauche ?

Pourquoi puis-je faire les opérations suivantes :

var b1, b2;

b1 = b2 = true;

document.write(b1," ", b2);
document.write("<br>");

b1 = !b2;

document.write(b1," ", b2);
document.write("<br>");

b1 = b2 = !true;

document.write(b1," ", b2);

Pourtant, lorsque j'essaie d'effectuer l'opération suivante, je reçois un message de type ReferenceError: invalid assignment left-hand side ?

var b1, b2;

b1 = !b2 = true;

document.write(b1," ", b2);

Il est évident que je ne peux pas le faire, mais je n'arrive pas à trouver une explication à cette impossibilité. Le site Guide du développeur MDN pour les états d'erreur :

Il y avait une mission inattendue quelque part. Cela peut être dû à une incompatibilité entre un opérateur d'affectation et un opérateur de comparaison, par exemple. Alors qu'un simple signe "=" affecte une valeur à une variable, les opérateurs "==" ou "===" comparent une valeur.

Tous les opérateurs d'affectation fonctionnent individuellement, comme cela a été prouvé, alors pourquoi ne peut-on pas les combiner en une opération unique / affectation en chaîne ?

13 votes

En réalité, vous essayez de faire : var b1, b2; !b2 = true; b1 = b2; ce qui est évidemment faux. Vous ne pouvez pas assigner une expression à une valeur...

0 votes

B2 n'est pas une fonction qui vérifie si c'est vrai ou faux vous devriez le mettre sur une parenthèse comme si vous faisiez une référence de chaînage de condition peut être vraie si elles ont des données égales

71voto

Li357 Points 31390

Quand vous essayez de faire ça :

var b1, b2;

b1 = !b2 = true;

document.write(b1, " ", b2);

Parce qu'ils sont fonctionnellement équivalents ‡ que vous êtes en train de faire :

var b1, b2;

!b2 = true;
b1 = true; //just the value of b2, not b2 itself

document.write(b1, " ", b2);

Dans la ligne !b2 = true vous essayez d'assigner une expression qui évalue une valeur (le côté gauche) à une valeur - cela n'a absolument aucun sens. Pensez-y de cette façon :

  • !b2 est affecté à true . !b2 est une expression et est évaluée comme un booléen. valeur non variable.
  • Cela reviendrait à faire 1 + 1 = 2 . Puisque 1 + 1 est évalué à un valeur vous ne pouvez pas l'attribuer à 2 une autre valeur. Vous devez attribuer une valeur à variable car l'affectation de valeur à valeur est sémantiquement et logiquement invalide.
  • Une autre façon de penser à ce qui précède est de réaliser ceci : 1 + 1 est une valeur. 2 est une valeur. Vous ne pouvez pas attribuer une valeur à une valeur, car cette dernière a déjà une valeur. Une constante telle que 2 a une valeur 2 il ne peut être modifié. Et si nous essayions 1 - 1 = 2 ? 0 une constante et une valeur, ne peut être 2 car c'est une constante.

Ainsi, il est sémantiquement et logiquement invalide d'attribuer une valeur à une valeur. Vous ne pouvez pas attribuer 0 a 2 tout comme vous ne pouvez pas assigner false a true .

Si vous souhaitez mieux comprendre la syntaxe et la sémantique, et savoir pourquoi cette méthode génère une erreur de type ReferenceError vous pouvez vous plonger dans le Spécification du langage ECMAScript® 2015 † . Selon le cahier des charges :

Section 12.14.1 - Opérateurs d'assignation - Sémantique statique : Erreurs précoces

AssignmentExpression : LeftHandSideExpression = AssignmentExpression

  • C'est une première Référence Erreur si LeftHandSideExpression n'est ni un ObjectLiteral ni un ArrayLiteral y IsValidSimpleAssignmentTarget de LeftHandSideExpression est fausse.

Dónde IsValidSimpleAssignmentTarget es:

Section 12.14.3 - Opérateurs d'assignation - Sémantique statique : IsValidSimpleAssignmentTarget

AssignmentExpression :
  YieldExpression
  ArrowFunction
  LeftHandSideExpression = AssignmentExpression
  LeftHandSideExpression AssignmentOperator AssignmentExpression

1. Faux retour.

Maintenant, regardez de nouveau votre code : b1 = !b2 = true . b1 = !b2 est bien parce que c'est LeftHandSideExpression = AssignmentExpression ce qui signifie que la réponse est vraie pour IsValidSimpleAssignmentTarget . Le problème se pose lorsque nous vérifions !b2 = true . Si nous regardons la définition de LeftHandSideExpression :

Section 12.3 - Expressions du côté gauche

Syntaxe

LeftHandSideExpression :
  NewExpression
  CallExpression

(Vous pouvez consulter les définitions de NewExpression y CallExpression dans le lien de spécification ci-dessus)

Vous pouvez voir que !b2 = true n'est pas un AssignmentExpression car il ne répond pas aux critères LeftHandSideExpression = AssignmentExpression . Cela s'explique par le fait que !b2 n'est pas un LeftHandSideExpression également pas un ObjectLiteral ni ArrayLiteral donc IsValidSimpleAssignmentTarget retourne false, ce qui déclenche la ReferenceError . Notez que l'erreur est une début erreur ce qui signifie qu'il est lancé avant l'exécution de tout code, comme indiqué dans le document intitulé Commentaire de @Bergi .


Vous pouvez lutter contre ce problème en procédant de l'une ou l'autre des manières suivantes, en fonction du résultat que vous souhaitez obtenir :

b1 = !(b2 = true);

Avec des parenthèses, l'intérieur des parenthèses a la priorité sur l'extérieur. De cette façon, b2 est attribué, et comme il est true à l'intérieur des parenthèses évalue à true . Ensuite, c'est équivalent à :

b1 = !(true);

Comme à l'intérieur des parenthèses est évalué à true comme indiqué ci-dessus. b1 sera l'opposé de b2 comme prévu, et b2 sera true .

Si vous vouliez b1 à être true y b2 à être false restructurer la déclaration comme suit :

b2 = !(b1 = true);

De cette façon, c'est l'exact opposé de ce qui précède, ce qui donne b1 = true et b2 = false .


‡ Comme @Bergi l'a mentionné dans les commentaires, b1 est affecté à l'opérande de droite, true dans ce cas, pas !b2 .

† Bien que la plupart des navigateurs ne prennent actuellement pas en charge toutes les fonctionnalités de l'ECMAScript 6 (2015), et utilisent plutôt ECMAScript 5.1 (2011) la spécification est la même pour les deux versions. Toutes les définitions sont les mêmes, et donc l'explication est toujours valable.

0 votes

D'un autre côté, je pense que l'intention de l'OP était de rendre b1 vrai et b2 faux.

1 votes

@DavidTheWin êtes-vous sûr ? b1 = !b2 = true On dirait qu'ils veulent !b2 pour être faux, ce qui signifie b2 doit être vrai et b1 être faux.

2 votes

Je l'ai lu comme "b1 et !b2 sont tous deux vrais" avec b2 étant donc faux

27voto

emileb Points 614
b1 = b2 = true;

est équivalent à

b2 = true;
b1 = true;

Un site L'affectation renvoie l'opérande de droite . C'est facile à voir dans une console interactive (telle que Outils de développement de Chrome , NodeJS , jsc ). Voir le spec détails dans la réponse d'Andrew .

node interactive console assignement return value example

Et quand vous essayez b1 = !b2 = true; l'équivalent n'a aucun sens :

(!b2) = true; // true = true; causes the error.
b1 = b2;      // never evaluated.

Cela s'explique par le fait que le ! prend préséance sur le = opérateur d'affectation comme le montrent les parenthèses dans (!b2) .

L'ordre est le suivant :

  1. b2 es undefined puisqu'il n'a pas encore été initialisé.
  2. Puis !b2 === true como !undefined === true donc !b2 devient true ,
  3. et ensuite l'affectation se produit, donc true = true .

Vous pouvez faire en sorte que cela fonctionne comme vous le souhaitez en ajoutant des parenthèses :

b1 = !(b2 = true);

1 votes

Merci pour la réponse, en particulier pour la référence à la préséance. Je ne comprends pas : !b2 = true; // true = true; pourquoi true = true alors que je n'ai pas encore attribué b2 ?

2 votes

@Zze parce que b2 === undefined au début. Puis !b2 === true como !undefined === true donc !b2 devient true et ensuite l'affectation se produit, donc true = true .

2 votes

En fait, c'est b1 = true; no b1 = b2; . Le résultat de l'opération d'affectation est simplement l'opérande de droite, sans que le côté gauche soit évalué. Cela n'a pas d'importance pour une simple variable lexicale, mais peut en avoir pour des cibles d'affectation plus complexes.

10voto

mrid Points 3723

L'expression b1 = !b2 = true; est évalué de droite à gauche

Premier : !b2 = true

alors : b1 = <result of previous assignment>

!b2 = true n'a pas de sens logique, d'où l'erreur.

Si vous écrivez b1 = b2 = true; il ne donnera pas d'erreur de ce type

0 votes

L'expression n'est jamais évaluée, car elle n'est pas syntaxiquement valide et génère une erreur précoce lors de l'analyse syntaxique.

3voto

prosti Points 4630

Pour ne citer que l'AST Affectation à la rvalue ( 1 ) ( 2 )

if (1 + 1 = 2)
 console.log("1 + 1 = 2");

var b1, b2;
b1 = !b2 = true;

pour confirmer l l'expression n'est jamais évaluée .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X