web-dev-qa-db-fra.com

Priorité des opérateurs avec l'opérateur Javascript ternaire

Je n'arrive pas à comprendre la première partie de ce code (+ =) en combinaison avec l'opérateur ternaire.

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

Je pense que ce code fonctionne comme suit:

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

Mais ce n'est pas correct car cela donne une erreur dans ma console.

Ma question est donc: comment dois-je interpréter ce code correctement?

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

Vous voulez que l'opérateur travaille pour h.className, mieux vaut être précis à ce sujet.
Bien sûr, aucun mal ne devrait venir de h.className += ' error', mais c'est une autre affaire.

Notez également que + a priorité sur l'opérateur ternaire: Préséance de l'opérateur JavaScript

141
Kobi

Pense-y de cette façon:

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

La façon dont l'instruction est exécutée est essentiellement la suivante:

  1. Est-ce que <expression> évaluer à vrai, ou est-ce que cela vaut faux?
  2. Si <expression> est évalué à true, puis la valeur de <true clause> est affecté à <variable>, <false clause> est ignoré et la prochaine instruction est exécutée.
  3. Si <expression> est évalué à false, puis <true clause> est ignoré et la valeur de <false clause> est affecté à <variable>.

La chose importante à réaliser avec l’opérateur ternaire dans cette langue et dans d’autres langues est que tout code contenu dans <expression> devrait produire un résultat booléen lors de l’évaluation: vrai ou faux.

Dans le cas de votre exemple, remplacez "assigné à" dans mon explication par "ajouté à", ou similaire pour l'arithmétique abrégée que vous utilisez, le cas échéant.

129
Wayne Koorts

Le += fait ce que vous voulez, mais dans la déclaration ternaire à sa droite, il vérifie si h.className _ est Falsey, ce qui serait le cas si elle n’était pas définie. Si c'est vrai (c'est-à-dire si un nom de classe est déjà spécifié), l'erreur est ajoutée avec un espace (c'est-à-dire l'ajout d'une classe nouvelle), sinon elle est ajoutée sans l'espace.

Le code peut être réécrit comme vous le suggérez, mais vous devez spécifier que h.className doit être utilisé pour la comparaison de la vérité, plutôt que pour utiliser sa valeur réelle, dans l'opérateur ternaire. Veillez donc à ne pas vous soucier de la concaténation des valeurs tout en effectuant votre opération ternaire:

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

Le côté droit de la = l'opérateur est évalué de gauche à droite. Alors,

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

est équivalent à

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

Être équivalent à

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

vous devez séparer la déclaration ternaire entre parenthèses

h.className = h.className + (h.className ? ' error' : 'error');
4
Justin Johnson
if (h.className) {
    h.className = h.className + ' error';
} else {
    h.className = h.className + 'error';
}

devrait être équivalent à:

h.className += h.className ? ' error' : 'error';
3
Darin Dimitrov

Je voudrais choisir l'explication de wayne:

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

Permet de considérer les deux cas:

case 1:
h.className += h.className ? 'true' : 'false'     
  • l'opérateur d'affectation fonctionne bien et la valeur est ajoutée
  • lors de la première exécution, o/p: false
  • 2ème fois. o/p: falsetrue - les valeurs continuent à être ajoutées

case2: h.className = h.className + h.className? 'vrai faux'

  • le résultat n'est pas identique au cas 1
  • lors de la première exécution, o/p: false
  • 2ème fois. o/p: false - les valeurs ne continuent pas à être ajoutées

explanation

Dans le code ci-dessus, le cas 1 fonctionne bien

alors que cas2:

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

h.className + h.className => considéré comme une expression pour un opérateur ternaire en tant qu’opérateur ternaire a la priorité la plus haute. oui, le résultat de l'expression ternaire est toujours attribué

Vous devez définir la priorité en utilisant des crochets

Vous devez définir l’ordre d’évaluation à considérer à l’aide de crochets pour que le cas 2 fonctionne comme le cas 1.

h.className = h.className + (h.className ? ' error' : 'error') 
1
Angelin Nadar

Je sais que la question est très ancienne, mais je ne suis pas satisfait à 100% des réponses, car elles semblent toutes incomplètes. Nous y revenons donc des premiers directeurs:

L'objectif général de l'utilisateur:

Résumer le code: "Je souhaite ajouter un nom de classe error à une chaîne, éventuellement avec un espace de début s'il y a déjà un nom de classe dans la chaîne."

Solution la plus simple

Comme Kobi l'a souligné, il y a 5 ans, disposer d'un espace de premier plan dans les noms de classe ne posera pas de problèmes avec les navigateurs connus. La solution la plus courte et correcte serait donc:

h.className += ' error';

Cela aurait dû être la réponse réelle au problème réel .


Quoi qu'il en soit, les questions posées étaient ...

1) Pourquoi cela a-t-il fonctionné?

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

L'opérateur conditionnel/ternaire fonctionne comme une instruction if, qui assigne le résultat de ses chemins true ou false à une variable.

Donc, ce code a fonctionné car il est évalué simplement comme:

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

2) et pourquoi cette pause?

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

La question dit "cela donne une erreur [n] dans ma console", ce qui peut vous induire en erreur en pensant que le code ne fonctionne pas . En fait, le code suivant est exécuté, sans erreur , mais renvoie simplement 'erreur' si la chaîne n'était pas vide et 'erreur' si la chaîne était vide et donc ne l'était pas répondre aux exigences .

Ce code donne toujours une chaîne contenant uniquement ' error' ou 'error' parce qu’il correspond à ce pseudo-code:

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

La raison en est que l'opérateur d'addition (+ au peuple commun) a une "préséance" (6) plus élevée que l'opérateur conditionnel/ternaire (15). Je sais que les nombres apparaissent à l'envers

La priorité signifie simplement que chaque type d'opérateur dans une langue est évalué dans un ordre prédéfini particulier (et pas seulement de gauche à droite).

Référence: Precedence d'opérateur Javascript

Comment changer l'ordre d'évaluation:

Maintenant que nous savons pourquoi cela échoue, vous devez savoir comment le faire fonctionner.

Certaines autres réponses parlent de changer la priorité , mais vous ne pouvez pas . La préséance est câblée dans la langue. Ceci est juste un ensemble de règles fixe ... Cependant, vous pouvez changer l'ordre d'évaluation ...

L'outil de notre boîte à outils permettant de modifier l'ordre d'évaluation est l'opérateur de regroupement (ou parenthèses). Pour ce faire, les expressions entre crochets sont évaluées avant les opérations en dehors des crochets. C'est tout ce qu'ils font, mais c'est assez.

Les crochets fonctionnent simplement parce qu’ils (opérateurs de regroupement) ont une priorité plus élevée que tous les autres opérateurs ("il existe maintenant un niveau 0").

En ajoutant simplement des crochets, vous modifiez l'ordre d'évaluation pour vous assurer que le test conditionnel est effectué en premier, avant la concaténation de chaînes simple:

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

Je laisse maintenant cette réponse à Rust invisible parmi les autres:)

1
Gone Coding