Explication de l'affectation des variables JavaScript OU (||)

351

Compte tenu de cet extrait de JavaScript ...

var a;
var b = null;
var c = undefined;
var d = 4;
var e = 'five';

var f = a || b || c || d || e;

alert(f); // 4

Quelqu'un peut-il m'expliquer comment s'appelle cette technique (ma meilleure estimation se trouve dans le titre de cette question!)? Et comment / pourquoi ça marche exactement?

Ma compréhension est que la variable se fverra attribuer la valeur la plus proche (de gauche à droite) de la première variable qui a une valeur qui n'est ni nulle ni indéfinie, mais je n'ai pas réussi à trouver beaucoup de matériel de référence sur cette technique et à avoir vu qu'il a utilisé beaucoup.

De plus, cette technique est-elle spécifique à JavaScript? Je sais que faire quelque chose de similaire en PHP aurait pour résultat d' favoir une vraie valeur booléenne, plutôt que la valeur d' delle - même.

chattsm
la source
4
Question ancienne, mais en ce qui concerne PHP, il y a une construction , vous pouvez utiliser: $f=$a or $f=$b or $f=$c; // etc. PHP a à la fois l' ||opérateur et l' oropérateur, qui font le même travail; cependant orest évalué après l' affectation tandis que ||est évalué avant. Cela vous donne également le style perlish de$a=getSomething() or die('oops');
Manngo
1
En PHP 5.3, vous pouvez laisser de côté la partie médiane de l'opérateur ternaire, en vous basant sur cela ... Vous pouvez également couper cela un peu plus court en quelque chose comme ceci: $f = $a ?: $b ?: $c;
Rei
1
Depuis PHP 7, vous pouvez l'utiliser ??pour cela. $a = $b ?? 'default'
Spencer Ruskin
@SpencerRuskin se $averra donc attribuer la valeur de $bsi $best vrai, autre 'default'?
oldboy
C'est vrai. Regardez la section des opérateurs de coalescence nulle sur cette page: php.net/manual/en/migration70.new-features.php
Spencer Ruskin

Réponses:

212

Voir l' évaluation des courts-circuits pour l'explication. C'est une façon courante de mettre en œuvre ces opérateurs; il n'est pas propre à JavaScript.

se détendre
la source
57
Faites attention au 'gotcha' qui est que le dernier sera toujours assigné même s'ils sont tous indéfinis, nuls ou faux. Définir quelque chose que vous savez n'est pas faux, nul ou indéfini à la fin de la chaîne est un bon moyen de signaler que rien n'a été trouvé.
Erik Reppen
Je vois cette technique depuis des années, mais ce qui m'a frappé à ce moment-là quand j'ai voulu l'utiliser, c'est que le résultat de l'expression n'est pas jeté à la booléenne. Vous ne pourrez pas le faire plus tard if( true == f ). Si un entier a été stocké dans f, ce test retournera toujours faux.
9
En fait, vous pouvez le faire if(true == f), ce qui revient au même if(f): le test passera. Si vous souhaitez également tester le type de f, utilisez une comparaison stricte:, if(true === f)qui échouera en effet.
Alsciende
5
Oui, l'évaluation des courts-circuits est courante. Mais la distinction réside ici dans la façon dont JavaScript renvoie la dernière valeur qui a interrompu l'exécution. @ La réponse d'Anurag explique bien mieux cela.
Ben.12
Je ne sais pas si c'est la meilleure explication pour les débutants. Je recommanderais: javascript.info/logical-operators
csguy
198

Ceci est fait pour assigner une valeur par défaut , dans ce cas la valeur de y, si la xvariable est fausse .

Les opérateurs booléens en JavaScript peuvent renvoyer un opérande, et pas toujours un résultat booléen comme dans d'autres langues.

L'opérateur OU logique ( ||) renvoie la valeur de son deuxième opérande, si le premier est faux, sinon la valeur du premier opérande est renvoyée.

Par exemple:

"foo" || "bar"; // returns "foo"
false || "bar"; // returns "bar"

Falsy valeurs sont celles qui contraignent à falsequand il est utilisé dans le contexte booléen, et ils sont 0, null, undefined, une chaîne vide, NaNet bien sûr false.

CMS
la source
1
+1 Y a-t-il un autre opérateur comme ça? Ou est ||exclusif.
OscarRyz
9
@Support (@Oscar): L' &&opérateur logique a un comportement similaire, il renvoie la valeur du premier opérande s'il est lui-même faux et renvoie la valeur du deuxième opérande, uniquement si le premier est véridique , par exemple ("foo" && "bar") == "bar"et(0 && "bar") == 0
CMS
12
Falsy est en fait le terme technique.
ChaosPandion
8
Nous avons donc entendu parler de ||, &&, "Falsy" et "Truly" dans cet article. Meilleure réponse avec des cadeaux "cachés".
Alex
4
@Alex NB: "Truthy" (! "Vraiment")
Bumpy
183

Javacript utilise l'évaluation des courts-circuits pour les opérateurs logiques ||et &&. Cependant, il est différent des autres langages en ce qu'il retourne le résultat de la dernière valeur qui a interrompu l'exécution, au lieu d'une valeur trueou false.

Les valeurs suivantes sont considérées comme fausses en JavaScript.

  • faux
  • nul
  • "" (chaîne vide)
  • 0
  • Nan
  • indéfini

En ignorant les règles de priorité des opérateurs et en gardant les choses simples, les exemples suivants montrent quelle valeur a interrompu l'évaluation et est retournée en conséquence.

false || null || "" || 0 || NaN || "Hello" || undefined // "Hello"

Les 5 premières valeurs jusqu'à NaNsont fausses donc elles sont toutes évaluées de gauche à droite, jusqu'à ce qu'elle rencontre la première valeur véridique - "Hello"ce qui rend toute l'expression vraie, donc tout ce qui est plus haut ne sera pas évalué et sera "Hello"renvoyé à la suite de l'expression . De même, dans ce cas:

1 && [] && {} && true && "World" && null && 2010 // null

Les 5 premières valeurs sont toutes véridiques et sont évaluées jusqu'à ce qu'elles rencontrent la première valeur falsifiée ( null), ce qui rend l'expression fausse, elle 2010n'est donc plus évaluée et nullest renvoyée à la suite de l'expression.

L'exemple que vous avez donné utilise cette propriété de JavaScript pour effectuer une affectation. Il peut être utilisé partout où vous avez besoin d'obtenir la première valeur véridique ou fausse parmi un ensemble de valeurs. Ce code ci-dessous attribuera la valeur "Hello"à bcar il facilite l'attribution d'une valeur par défaut, au lieu de faire des vérifications if-else.

var a = false;
var b = a || "Hello";

Vous pouvez appeler l'exemple ci-dessous une exploitation de cette fonctionnalité, et je pense que cela rend le code plus difficile à lire.

var messages = 0;
var newMessagesText = "You have " + messages + " messages.";
var noNewMessagesText = "Sorry, you have no new messages.";
alert((messages && newMessagesText) || noNewMessagesText);

À l'intérieur de l'alerte, nous vérifions si messagesc'est faux, et si oui, évaluons et retournons noNewMessagesText, sinon évaluons et retournons newMessagesText. Comme c'est faux dans cet exemple, nous nous arrêtons à noNewMessagesText et alertons "Sorry, you have no new messages.".

Anurag
la source
36
C'est la meilleure réponse à mon avis en raison de l'explication suivante:However, it's different to other languages in that it returns the result of the last value that halted the execution, instead of a true, or false value.
mastazi
1
@mastazi Yep, il devrait apparaître en caractères gras IMHO.
noober le
6
Devrait être la réponse, elle montre les valeurs choisies sur les cas de test.
Dadan
D'accord, c'est ma réponse préférée car elle répond spécifiquement aux problèmes d'affectation des variables JavaScript. En outre, si vous choisissez d'utiliser un ternaire comme l'une des variables suivantes pour tester l'affectation (après l'opérateur), vous devez encapsuler le ternaire entre parenthèses pour que l'évaluation de l'affectation fonctionne correctement.
Joey T
cela devrait être la réponse acceptée
Alan
49

Les variables Javascript ne sont pas typées, donc f peut se voir attribuer une valeur entière même si elle a été attribuée via des opérateurs booléens.

f reçoit la valeur la plus proche qui n'est pas équivalente à false . Donc 0, faux, null, non défini, sont tous passés:

alert(null || undefined || false || '' || 0 || 4 || 'bar'); // alerts '4'
Alsciende
la source
13
N'oubliez pas ''également faux égal dans ce cas.
Brigand
Upvote pour avoir souligné ce f is assigned the NEAREST valuequi est un point assez important ici.
steviejay
3
"Nearest" n'est pas tout à fait vrai, bien qu'il ait cette apparence. L' ||opérateur booléen , étant un opérateur booléen, a deux opérandes: un côté gauche et un côté droit. Si le côté gauche du ||est vrai , l'opération se résout au côté gauche et le côté droit est ignoré. Si le côté gauche est faux , il se résout au côté droit. Donc, null || undefined || 4 || 0se résout réellement à undefined || 4 || 0qui se résout à 4 || 0qui se résout 4.
devios1
29

Il n'y a pas de magie. Les expressions booléennes comme a || b || c || dsont paresseusement évaluées. Interpeter recherche la valeur de a, elle n'est pas définie, elle est donc fausse alors elle bcontinue , puis elle voit ce qui est nul, ce qui donne toujours un résultat faux alors elle continue, puis elle voit c- même histoire. Enfin, il voit det dit «hein, ce n'est pas nul, j'ai donc mon résultat» et il l'assigne à la variable finale.

Cette astuce fonctionnera dans tous les langages dynamiques qui effectuent une évaluation par court-circuit paresseux des expressions booléennes. Dans les langages statiques, il ne se compile pas (erreur de type). Dans les langages désireux d'évaluer des expressions booléennes, il retournera une valeur logique (c'est-à-dire vrai dans ce cas).

Marcin
la source
6
Dans le langage assez statique C # on peut utiliser le ?? opérateur á la: objet f = a ?? b ?? c ?? ré ?? e;
herzmeister
2
herzmeister - merci! Je ne savais pas ça ?? l'opérateur peut être enchaîné en C # et utilisé dans les techniques d'évaluation paresseuse
Marek
3
Comme mentionné ailleurs, ce dernier dsera attribué qu'il soit nul / non défini ou non.
BlackVegetable
Une légère correction: l' ||opérateur se résout toujours à tout l'opérande du côté droit lorsque le côté gauche est faux. Étant un opérateur booléen, il ne voit que deux entrées: le côté gauche et le côté droit. L'analyseur ne les considère pas comme une série de termes, donc il ne s'arrête pas réellement lorsqu'il trouve la première valeur véridique à moins que cette valeur ne soit également l'opérande gauche d'un autre ||.
devios1
8

Cette question a déjà reçu plusieurs bonnes réponses.

En résumé, cette technique tire parti d'une caractéristique de la façon dont le langage est compilé. Autrement dit, JavaScript «court-circuite» l'évaluation des opérateurs booléens et renvoie la valeur associée à la première valeur de variable non fausse ou à ce que contient la dernière variable. Voir l'explication d'Anurag de ces valeurs qui seront évaluées comme fausses.

L'utilisation de cette technique n'est pas une bonne pratique pour plusieurs raisons; toutefois.

  1. Lisibilité du code: cela utilise des opérateurs booléens, et si le comportement de la façon dont cela se compile n'est pas compris, le résultat attendu serait une valeur booléenne.
  2. Stabilité: cela utilise une fonctionnalité de compilation du langage qui n'est pas cohérente dans plusieurs langues, et pour cette raison, c'est quelque chose qui pourrait potentiellement être ciblé pour un changement à l'avenir.
  3. Fonctionnalités documentées: Il existe une alternative existante qui répond à ce besoin et est cohérente dans plusieurs langues. Ce serait l'opérateur ternaire:

    ()? valeur 1: valeur 2.

L'utilisation de l'opérateur ternaire nécessite un peu plus de frappe, mais il distingue clairement entre l'expression booléenne évaluée et la valeur attribuée. De plus, il peut être chaîné, de sorte que les types d'affectations par défaut exécutées ci-dessus pourraient être recréés.

var a;
var b = null;
var c = undefined;
var d = 4;
var e = 'five';

var f =  ( a ) ? a : 
                ( b ) ? b :
                       ( c ) ? c :
                              ( d ) ? d :
                                      e;

alert(f); // 4
WSimpson
la source
potentially be targeted for change in the future.oui, mais ce n'est pas le cas pour le javascript.
Dadan
Je suis venu ici et j'ai vu toutes les réponses ci-dessus et je me suis dit que quelque chose semblait juste au sujet de la mission. Je viens de lire Clean Code de Robert C Martin et ce type de mission viole définitivement la règle "N'a pas d'effets secondaires" ... alors que l'auteur lui-même déclare que son livre n'est qu'une des nombreuses techniques pour générer du bon code, je était toujours surpris que personne d'autre ne s'oppose à ce genre de mission. +1
Albert Rothman
Merci pour votre réponse. Je pense que plus de gens doivent considérer les effets secondaires lors de l'écriture de code, mais jusqu'à ce que quelqu'un ait passé beaucoup de temps à maintenir le code des autres. Souvent, ils ne le considèrent pas.
WSimpson
1
Vous pensez vraiment que la monstruosité est plus claire que a || b || c || d || e?
devios1
1
@AlbertRothman Je ne vois aucun effet secondaire. Rien n'est muté. C'est simplement un raccourci pour la fusion nulle, ce qui est une caractéristique assez courante dans de nombreuses langues.
devios1
7

Renvoie la première valeur vraie de la sortie .

Si tous sont faux, retournez la dernière fausse valeur.

Exemple:-

  null || undefined || false || 0 || 'apple'  // Return apple
Arshid KV
la source
4

Il définit la nouvelle variable ( z) à la valeur de xsi elle est "véridique" (non nulle, un objet / tableau / fonction valide / quoi que ce soit) ou yautre. C'est une façon relativement courante de fournir une valeur par défaut au cas où il xn'existe pas.

Par exemple, si vous avez une fonction qui prend un paramètre de rappel facultatif, vous pouvez fournir un rappel par défaut qui ne fait rien:

function doSomething(data, callback) {
    callback = callback || function() {};
    // do stuff with data
    callback(); // callback will always exist
}
Matthew Crumley
la source
1

Cela signifie que si xest défini, la valeur de zsera x, sinon si yest défini, sa valeur sera définie comme la zvaleur de.

c'est la même chose que

if(x)
  z = x;
else
  z = y;

C'est possible parce que les opérateurs logiques en JavaScript ne renvoient pas de valeurs booléennes mais la valeur du dernier élément nécessaire pour terminer l'opération (dans une phrase OU ce serait la première valeur non fausse, dans une phrase ET ce serait la dernière ). Si l'opération échoue, elle falseest renvoyée.

Andris
la source
5
c'est faux! si (x) {z = x; } else {z = y;} si la première valeur est fausse, la deuxième valeur est toujours attribuée sans dépendre de la valeur réelle.
evilpie
Sauf que je pense qu'il assigne simplement y à z si x est faux . C'est la façon dont cela fonctionne pour moi dans FF, bien sûr, qui pourrait également dépendre de l'implémentation.
tvanfosson
7
La dernière partie sur le retour de faux n'est pas vraie (sans jeu de mots). Si la première valeur est falsey, l' ||opérateur renvoie simplement la deuxième valeur, qu'elle soit véridique ou non.
Matthew Crumley
-1. Votre extrait de code équivalent est précis, mais le point important est qu'il zest défini sur la valeur de xsi cette valeur est véridique . Sinon, il prend la valeur de y. Cela signifie que si xest défini sur, par exemple, 0ou sur la chaîne vide "", cela ne fait pas ce que vous dites, car ces valeurs sont fausses .
Daniel Cassidy
1

Son appelé opérateur de court-circuit.

L'évaluation de court-circuit indique que le deuxième argument n'est exécuté ou évalué que si le premier argument ne suffit pas pour déterminer la valeur de l'expression. lorsque le premier argument de la fonction OR (||) est évalué à vrai, la valeur globale doit être vraie.

Il pourrait également être utilisé pour définir une valeur par défaut pour l'argument de la fonction. »

function theSameOldFoo(name){ 
  name = name || 'Bar' ;
  console.log("My best friend's name is " + name);
}
theSameOldFoo();  // My best friend's name is Bar
theSameOldFoo('Bhaskar');  // My best friend's name is Bhaskar`
Vijay
la source
0

Il évaluera X et, si X n'est pas nul, la chaîne vide ou 0 (faux logique), il l'affectera à z. Si X est nul, la chaîne vide ou 0 (faux logique), alors il attribuera y à z.

var x = '';
var y = 'bob';
var z = x || y;
alert(z);

Sortira «bob»;

tvanfosson
la source
Vous devez clarifier ce que vous entendez par «vide». Les chaînes vides se contraignent false, mais les tableaux ou objets vides se contraignent true.
Daniel Cassidy
@Daniel "null, empty ou 0" - null s'appliquerait en ce qui concerne les tableaux et les objets. Point pris, cependant.
tvanfosson
0

Selon le blog de Bill Higgins ; l'idiome d'affectation OU logique Javascript (février 2007), ce comportement est vrai à partir de la version 1.2 (au moins)

Il suggère également une autre utilisation (citée): " normalisation légère des différences entre navigateurs "

// determine upon which element a Javascript event (e) occurred
var target = /*w3c*/ e.target || /*IE*/ e.srcElement;
Alon Brontman
la source