46 votes

Pourquoi "(foo) = "bar"`` est-il légal en JavaScript ?

Dans le REPL de Node.js (testé également dans SpiderMonkey) la séquence

var foo = null;
(foo) = "bar";

est valable, avec foo ultérieurement égale à "bar" à l'opposé de null .

Cela semble contre-intuitif car on pourrait penser que la parenthèse déréférence au moins bar et de jeter Côté gauche invalide dans l'affectation` .

Naturellement, lorsque vous faites quelque chose d'intéressant, cela échoue de la manière susmentionnée.

(foo, bar) = 4
(true ? bar : foo) = 4

Selon ECMA-262 sur les expressions de la main gauche (pour autant que je puisse l'interpréter) il n'y a pas de non-terminaux valides qui permettraient d'accepter une parenthèse.

Y a-t-il quelque chose que je ne vois pas ?

28voto

Bergi Points 104242

C'est valable en effet. Vous avez le droit d'envelopper toute cible d'affectation simple entre parenthèses.

La partie gauche de la = L'opération est une LeftHandSideExpression comme vous l'avez correctement identifié. Cela peut être retracé à travers les différents niveaux de précendance ( NewExpression , MemberExpression ) à un PrimaryExpression qui, à son tour, pourrait être un Cover­Parenthesized­Expression­And­Arrow­Parameter­List :

( Expression[In, ?Yield])

(en fait, lorsqu'il est analysé avec la cible PrimaryExpression c'est un ParenthesizedExpression ).

Donc c'est valable au niveau de la grammaire, au moins. La validité de la syntaxe JS est déterminée par un autre facteur : la sémantique statique des erreurs précoces. Il s'agit essentiellement de règles de prose ou d'algorithme qui rendent certaines expansions de production invalides (erreurs de syntaxe) dans certains cas. Cela a par exemple permis aux auteurs de réutiliser les grammaires des initialisateurs de tableaux et d'objets pour la déstructuration, mais en appliquant seulement certaines règles. Dans le erreurs précoces pour les expressions d'affectation nous trouvons

C'est une première Reference Error si LeftHandSideExpression n'est ni un ObjectLiteral ni un ArrayLiteral y IsValidSimpleAssignmentTarget de LeftHandSideExpression es false .

Nous pouvons également constater cette distinction dans le évaluation des expressions d'affectation où les cibles d'assignation simples sont évaluées en une référence qui peut être assignée, au lieu d'obtenir les éléments du modèle de déstructuration comme les littéraux d'objets et de tableaux.

Alors qu'est-ce que cela IsValidSimpleAssignmentTarget faire pour Expressions du côté gauche ? En gros, il autorise les affectations aux accès aux propriétés et interdit les affectations aux expressions d'appel. Il n'y a pas d'indication concernant les PrimaryExpressions qui ont leur propre règle IsValidSimpleAssignmentTarget . Tout ce qu'il fait, c'est d'extraire le Expression entre les parenthèses jusqu'au Opération de CoveredParenthesizedExpression puis vérifiez à nouveau IsValidSimpleAssignmentTarget. En bref : (…) = … est valable lorsque … = … est valide. Cela donnera true seulement pour Identifiants (comme dans votre exemple) et les propriétés.

15voto

TERMtm Points 1021

Conformément à Suggestion de @dlatikay en suivant une intuition existante, une recherche sur CoveredParenthesizedExpression a permis de mieux comprendre ce qui se passe ici.

Apparemment, la raison pour laquelle un non-terminal ne peut pas être trouvé dans la base de données des spec pour expliquer pourquoi (foo) est acceptable en tant que LeftHandExpression est étonnamment simple. Je suppose que vous comprenez comment fonctionnent les analyseurs syntaxiques, et qu'ils fonctionnent en deux étapes distinctes : Lexing y Analyse syntaxique .

Ce que j'ai appris de cette petite recherche, c'est que la construction (foo) n'est pas techniquement livré à l'analyseur syntaxique, et donc au moteur, comme vous pourriez le penser.

Considérez les points suivants

var foo = (((bar)));

Comme nous le savons tous, une telle chose est parfaitement légale. Pourquoi ? Eh bien, visuellement, vous pouvez juste ignorer la parenthèse alors que l'affirmation reste parfaitement logique.

De même, voici un autre exemple valable, même du point de vue de la lisibilité humaine, car les parenthèses n'explicitent que ce que PEMDAS rend déjà implicite.

(3 + ((4 * 5) / 2)) === 3 + 4 * 5 / 2
>> true

On peut en déduire une observation clé, si l'on comprend comment les analyseurs syntaxiques fonctionnent déjà. (rappelez-vous, Javascript est toujours analysé ( lire : compilé ) et puis run) Donc, dans un sens direct, ces parenthèses sont "énoncer l'évidence" .

Donc, tout cela étant dit, que se passe-t-il exactement ?

En gros, les parenthèses (à l'exception des paramètres de fonction) sont regroupées en fonction des symboles qui les contiennent. En termes simples, cela signifie que les parenthèses ne sont interprétées que pour guider l'analyseur syntaxique dans le regroupement de ce qu'il lit. Si le contexte des parenthèses est déjà "en ordre", et ne nécessite donc aucune modification de l'information émise par l'analyseur. AST le code (machine) est alors émis comme si ces parenthèses n'existaient pas du tout.

L'analyseur est plus ou moins paresseux, en supposant que les parenthèses sont impertinentes. (ce qui dans ce cas limite, n'est pas vrai)

Ok, et où cela se passe-t-il exactement ?

Selon 12.2.1.5 Sémantique statique : IsValidSimpleAssignmentTarget dans la spécification,

PrimaryExpression : (CouvertureParenthesizedExpressionAndArrowParameterList)

  1. Soit expr une expression couverte de CoverParenthesizedExpressionAndArrowParameterList.
  2. Retourne IsValidSimpleAssignmentTarget de expr.

I.E. Si vous attendez primaryExpression retourner ce qui se trouve à l'intérieur de la parenthèse et l'utiliser.

Pour cette raison, dans ce scénario, il ne convertit pas (foo) en CoveredParenthesizedExpression{ inner: "foo" } il le convertit simplement en foo ce qui préserve le fait qu'il s'agit d'un Identifier et donc syntaxiquement, sans être nécessairement lexical valable.

TL;DR

C'est wat.

Vous voulez en savoir un peu plus ?

Vérifiez La réponse de @Bergi .

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