Qu'est-ce que la construction x = x || tu veux dire?

250

Je débogue du JavaScript et je ne peux pas expliquer ce que cela ||fait?

function (title, msg) {
  var title = title || 'Error';
  var msg   = msg || 'Error on Request';
}

Quelqu'un peut-il me donner un indice, pourquoi ce type utilise- var title = title || 'ERROR't-il? Je le vois parfois aussi sans vardéclaration.

opHASnoNAME
la source
44
Les gens ont déjà répondu à cela ... mais soyez extrêmement conscients du fait que la deuxième valeur est choisie si la première valeur est falsy, pas JUSTE undefined. Le nombre de fois que j'ai vu doWeDoIt = doWeDoIt || truesuffit à me faire pleurer. (c'est-à doWeDoIt- dire qu'il ne le sera plus false)
Matt
4
Pour ceux qui ont une expérience avec C #, l'opérateur double-pipe est équivalent à l'opérateur null-coalesce ??. Javascript évalue les objets non nuls comme true (ou mieux évalue les objets nuls à faux)
usr-local-ΕΨΗΕΛΩΝ
3
Ne vous sentez pas mal - JS est le seul langage maladroit permettant cet horrible codage ... cela et l'enseignement qu'il est approprié d'imbriquer chaque fonction dans des lignes de code et de les jeter, les rendant jetables et inutilisables une deuxième fois. :) J'ai 30 ans dans le codage et je n'ai pas touché JS jusqu'à il n'y a pas longtemps moi-même et je ressens votre douleur tout ce que je peux dire, c'est de garder un "ça n'a pas de sens, c'est seulement dans JS", c'est la seule façon dont je '' ai réussi! :)
Collin Chaffin
1
Veuillez envisager de remplacer la réponse acceptée par ma réponse .
Michał Perłakowski

Réponses:

211

Cela signifie que l' titleargument est facultatif. Donc, si vous appelez la méthode sans argument, elle utilisera une valeur par défaut de "Error".

C'est un raccourci pour écrire:

if (!title) {
  title = "Error";
}

Ce genre de raccourci avec des expressions booléennes est également courant en Perl. Avec l'expression:

a OR b

il évalue truesi l'un aou l' autre l' best true. Donc, si ac'est vrai, vous n'avez pas besoin de vérifier bdu tout. C'est ce qu'on appelle l'évaluation booléenne en court-circuit:

var title = title || "Error";

vérifie essentiellement si titleévalue à false. Si c'est le cas, il "revient" "Error", sinon il revient title.

cletus
la source
3
Désolé d'être pointilleux, mais l'argument n'est pas facultatif, l'argument est vérifié
themightybun
4
Ce n'est PAS la réponse et je suis d'accord avec le dernier commentaire, ce n'est même pas facultatif. Aucune partie de cette réponse n'est correcte, même la référence Perl, car l'instruction Perl fait réellement SENSE et est évaluée d'une manière complètement différente. Le JS est eval dans une méthode de logique booléenne beaucoup plus "convertie" que moi aussi trouve beaucoup plus déroutante à lire / écrire. La réponse ci-dessous intitulée "Qu'est-ce que l'opérateur de double tuyau" est en fait une bonne réponse.
Collin Chaffin
198

Qu'est-ce que l'opérateur double tuyau ( ||)?

L'opérateur double pipe ( ||) est l' opérateur logiqueOR . Dans la plupart des langues, cela fonctionne de la manière suivante:

  • Si la première valeur est false, il vérifie la deuxième valeur. S'il l'est true, il revient trueet s'il l'est false, il revient false.
  • Si la première valeur est true, elle revient toujours true, quelle que soit la seconde valeur.

Donc, fondamentalement, cela fonctionne comme cette fonction:

function or(x, y) {
  if (x) {
    return true;
  } else if (y) {
    return true;
  } else {
    return false;
  }
}

Si vous ne comprenez toujours pas, regardez ce tableau:

      | true   false  
------+---------------
true  | true   true   
false | true   false  

En d'autres termes, ce n'est faux que lorsque les deux valeurs sont fausses.

En quoi est-ce différent en JavaScript?

JavaScript est un peu différent, car c'est un langage peu typé . Dans ce cas, cela signifie que vous pouvez utiliser l' ||opérateur avec des valeurs qui ne sont pas booléennes. Bien que cela n'ait aucun sens, vous pouvez utiliser cet opérateur avec par exemple une fonction et un objet:

(function(){}) || {}

Que se passe-t-il là?

Si les valeurs ne sont pas booléennes, JavaScript effectue une conversion implicite en booléen . Cela signifie que si la valeur est Falsey (par exemple 0, "", null, undefined(voir aussi toutes les valeurs de Falsey en JavaScript )), il sera considéré comme false; sinon, il est traité comme true.

Donc l'exemple ci-dessus devrait donner true, car la fonction vide est véridique. Et bien non. Il renvoie la fonction vide. C'est parce que l' ||opérateur de JavaScript ne fonctionne pas comme je l'ai écrit au début. Cela fonctionne de la manière suivante:

  • Si la première valeur est falsey , elle renvoie la deuxième valeur .
  • Si la première valeur est véridique , elle renvoie la première valeur .

Surpris? En fait, il est "compatible" avec l' ||opérateur traditionnel . Il pourrait être écrit comme la fonction suivante:

function or(x, y) {
  if (x) {
    return x;
  } else {
    return y;
  }
}

Si vous passez une valeur véridique as x, cela renvoie x, c'est-à-dire une valeur véridique. Donc, si vous l'utilisez plus tard dans la ifclause:

(function(x, y) {
  var eitherXorY = x || y;
  if (eitherXorY) {
    console.log("Either x or y is truthy.");
  } else {
    console.log("Neither x nor y is truthy");
  }
}(true/*, undefined*/));

vous obtenez "Either x or y is truthy.".

Si xc'était Falsey, ce eitherXorYserait y. Dans ce cas, vous obtiendrez le "Either x or y is truthy."si yétait vrai; sinon vous auriez "Neither x nor y is truthy".

La vraie question

Maintenant, quand vous savez comment ||fonctionne l'opérateur, vous pouvez probablement comprendre par vous-même ce que cela x = x || ysignifie. Si xest véridique, xest affecté à x, donc en réalité rien ne se passe; sinon yest affecté à x. Il est couramment utilisé pour définir les paramètres par défaut dans les fonctions. Cependant, il est souvent considéré comme une mauvaise pratique de programmation , car il vous empêche de passer une valeur de falsey (qui n'est pas nécessairement undefinedou null) comme paramètre. Prenons l'exemple suivant:

function badFunction(/* boolean */flagA) {
  flagA = flagA || true;
  console.log("flagA is set to " + (flagA ? "true" : "false"));
}

Il semble valide à première vue. Cependant, que se passerait-il si vous passiez falseen flagAparamètre (car c'est booléen, c'est-à-dire peut être trueou false)? Cela deviendrait true. Dans cet exemple, il n'y a aucun moyen de définir flagAsur false.

Ce serait une meilleure idée de vérifier si explicitement flagAest undefined, comme ça:

function goodFunction(/* boolean */flagA) {
  flagA = typeof flagA !== "undefined" ? flagA : true;
  console.log("flagA is set to " + (flagA ? "true" : "false"));
}

Bien qu'il soit plus long, il fonctionne toujours et il est plus facile à comprendre.


Vous pouvez également utiliser la syntaxe ES6 pour les paramètres de fonction par défaut , mais notez qu'elle ne fonctionne pas dans les navigateurs plus anciens (comme IE). Si vous souhaitez prendre en charge ces navigateurs, vous devez transpiler votre code avec Babel .

Voir aussi Opérateurs logiques sur MDN .

Michał Perłakowski
la source
13
+1 - de loin la réponse la plus correcte et la plus complète. Et, pour ceux qui ont cette question (certains d'entre nous, anciens codeurs chevronnés de JS inclus) devraient certainement se concentrer le plus sur toute cette réponse sur cette ligne: "Bien que cela n'a aucun sens" parce que ce "typage lâche" n'aura tout simplement jamais de sens à ceux d'entre nous qui ont grandi sans. Pour nous, un opérateur booléen est juste cela et SEULEMENT que ...... et quiconque a pensé que ce serait une bonne idée de devoir s'arrêter et réfléchir à une conversion farfelue de valeurs non booléennes en booléen tout en lisant / écrivant du code , j'ai oublié de prendre leurs médicaments ce jour-là! :)
Collin Chaffin
2
+1, en bref: title = title || 'Error'signifieif (title) { title = title; } else { title = 'Error'; }
Andre Elrico
En fait, je ne suis pas d'accord avec la ligne "même si cela n'a aucun sens". Je comprends que la ligne ne se compilerait pas en C, par exemple, mais elle est bien comprise si vous venez de Ruby par exemple, ou même de Groovy. En Ruby, vous pouvez l'exprimer encore plus court, comme title ||= 'Error'.
Elliot Nelson
28

Si le titre n'est pas défini, utilisez 'ERREUR' comme valeur par défaut.

Plus générique:

var foobar = foo || default;

Lit: Réglez foobar sur fooou default. Vous pouvez même enchaîner cela plusieurs fois:

var foobar = foo || bar || something || 42;
ericteubert
la source
1
J'ai trouvé cela déroutant car les variables ont le même nom. Beaucoup plus facile quand ils ne le font pas.
Norbert Norbertson
14

Expliquant cela un peu plus ...

L' ||opérateur est l' oropérateur logique . Le résultat est vrai si la première partie est vraie et il est vrai si la deuxième partie est vraie et il est vrai si les deux parties sont vraies. Pour plus de clarté, le voici dans un tableau:

 X | Y | X || Y 
---+---+--------
 F | F |   F    
---+---+--------
 F | T |   T    
---+---+--------
 T | F |   T    
---+---+--------
 T | T |   T    
---+---+--------

Maintenant, remarquez quelque chose ici? Si Xest vrai, le résultat est toujours vrai. Donc, si nous savons que Xc'est vrai, nous n'avons pas du tout à vérifier Y. De nombreux langages mettent ainsi en œuvre des évaluateurs de "court-circuit" pour les logiques or(et logiques) andvenant de l'autre sens. Ils vérifient le premier élément et si c'est vrai, ils ne prennent pas la peine de vérifier le second. Le résultat (en termes logiques) est le même, mais en termes d'exécution, il y a potentiellement une énorme différence si le deuxième élément est coûteux à calculer.

Alors qu'est-ce que cela a à voir avec votre exemple?

var title   = title || 'Error';

Regardons ça. L' titleélément est transmis à votre fonction. En JavaScript, si vous ne transmettez pas de paramètre, il prend par défaut une valeur nulle. Également en JavaScript, si votre variable est une valeur nulle, elle est considérée comme fausse par les opérateurs logiques. Donc, si cette fonction est appelée avec un titre donné, il s'agit d'une valeur non fausse et donc affectée à la variable locale. Si toutefois on ne lui donne pas de valeur, c'est une valeur nulle et donc fausse. L' oropérateur logique évalue ensuite la deuxième expression et renvoie à la place «Erreur». Alors maintenant, la variable locale reçoit la valeur «Erreur».

Cela fonctionne en raison de l'implémentation d'expressions logiques en JavaScript. Il ne retourne pas une valeur booléenne correcte ( trueou false) mais renvoie à la place la valeur qui lui a été donnée par certaines règles quant à ce qui est considéré comme équivalent trueet à ce qui est considéré comme équivalent false. Recherchez votre référence JavaScript pour savoir ce que JavaScript considère comme vrai ou faux dans des contextes booléens.

JUSTE MON AVIS correct
la source
8

Le double tuyau signifie "OU" logique. Ce n'est pas vraiment le cas lorsque le "paramètre n'est pas défini", car strictement dans le javascript si vous avez du code comme celui-ci:

function foo(par) {
}

Appelle ensuite

foo()
foo("")
foo(null)
foo(undefined)
foo(0)

ne sont pas équivalents.

Double pipe (||) transtypera le premier argument en booléen et si le booléen résultant est vrai - faites l'affectation sinon il assignera la bonne partie.

Cela est important si vous vérifiez le paramètre non défini.

Disons que nous avons une fonction setSalary qui a un paramètre facultatif. Si l'utilisateur ne fournit pas le paramètre, la valeur par défaut de 10 doit être utilisée.

si vous faites la vérification comme ceci:

function setSalary(dollars) {
    salary = dollars || 10
}

Cela donnera un résultat inattendu sur appel comme

setSalary(0) 

Il fixera toujours le 10 en suivant le flux décrit ci-dessus.

Juriy
la source
8

Fondamentalement, il vérifie si la valeur avant le || évalue à true, si oui, il prend cette valeur, sinon, il prend la valeur après le ||.

Valeurs pour lesquelles il prendra la valeur après le || (Autant que je m'en souvienne):

  • indéfini
  • faux
  • 0
  • '' (Chaîne nulle ou nulle)
Morfildur
la source
1
faux || null || indéfini || 0 || '' || 'vous avez oublié null'
Dziamid
7

Bien que la réponse de Cletus soit correcte, je pense que plus de détails devraient être ajoutés en ce qui concerne "évalue à faux" dans JavaScript.

var title = title || 'Error';
var msg   = msg || 'Error on Request';

Ce n'est pas seulement de vérifier si le titre / msg a été fourni, mais aussi si l'un ou l'autre est faux . c'est-à-dire l'un des suivants:

  • faux.
  • 0 (zéro)
  • "" (chaîne vide)
  • nul.
  • indéfini.
  • NaN (une valeur numérique spéciale signifiant Pas un nombre!)

Donc dans la ligne

var title = title || 'Error';

Si le titre est véridique (c'est-à-dire pas faux, donc title = "titleMessage" etc.), alors l'opérateur booléen OR (||) a trouvé une valeur "vraie", ce qui signifie qu'il est évalué comme vrai, donc il court-circuite et renvoie la vraie valeur (titre).

Si le titre est faux (c'est-à-dire l'une des listes ci-dessus), alors l'opérateur booléen OU (||) a trouvé une valeur "fausse" et doit maintenant évaluer l'autre partie de l'opérateur, "Erreur", qui est évaluée comme vraie , et est donc retourné.

Il semblerait également (après une expérimentation rapide de la console Firebug) que les deux côtés de l'opérateur évaluent à faux, il renvoie le deuxième opérateur «falsy».

c'est à dire

return ("" || undefined)

renvoie indéfini, c'est probablement pour vous permettre d'utiliser le comportement demandé dans cette question lorsque vous essayez de définir le titre / message par défaut sur "". c'est à dire après avoir couru

var foo = undefined
foo = foo || ""

foo serait réglé sur ""

Azrantha
la source
5

opérateur de double tuyauterie

cet exemple est-il utile?

var section = document.getElementById('special');
if(!section){
     section = document.getElementById('main');
}

peut également être

var section = document.getElementById('special') || document.getElementById('main');
choix
la source
4

Pour ajouter quelques explications à tout ce qui a été dit avant moi, je devrais vous donner quelques exemples pour comprendre les concepts logiques.

var name = false || "Mohsen"; # name equals to Mohsen
var family = true || "Alizadeh" # family equals to true

Cela signifie que si le côté gauche est évalué comme une instruction vraie, il sera terminé et le côté gauche sera renvoyé et affecté à la variable. dans d'autres cas, le côté droit sera retourné et attribué.

Et l' opérateur a la structure opposée comme ci-dessous.

var name = false && "Mohsen" # name equals to false
var family = true && "Alizadeh" # family equals to Alizadeh
Mohsen Alizadeh
la source
3

|| est l'opérateur booléen OR. Comme en javascript, undefined, null, 0, false sont considérés comme des valeurs fausses .

Cela signifie simplement

true || true = true
false || true = true
true || false = true
false || false = false

undefined || "value" = "value"
"value" || undefined = "value"
null || "value" = "value"
"value" || null = "value"
0 || "value" = "value"
"value" || 0 = "value"
false || "value" = "value"
"value" || false = "value"
Shivang Gupta
la source
2

Citation: "Que signifie la construction x = x || y?"

Attribution d'une valeur par défaut.

Cela signifie fournir une valeur par défaut de y à x , au cas où x attend toujours sa valeur mais ne l'a pas encore reçue ou a été délibérément omis afin de revenir à une valeur par défaut.

Bekim Bacaj
la source
C'est la signification exacte de la construction et la seule signification de celle-ci. Et c'était largement comme un sous-programme dans l'écriture de fonctions qui pouvaient être récupérées en tant que prototypes, fonctions autonomes et également en tant que méthodes empruntées à appliquer sur un autre élément. Où son principal et unique devoir était de modifier la référence de la cible. Exemple: function getKeys(x) { x = x || this ; .... }qui pourrait être utilisé sans modification comme fonction autonome, comme méthode de propriété dans les prototypes et comme méthode d'un élément qui peut obtenir un autre élément comme argument comme `[[element] .getKeys (anotherElement);`
Bekim Bacaj
-5

Et je dois ajouter une dernière chose: ce morceau de sténographie est une abomination. Il utilise abusivement une optimisation accidentelle de l'interpréteur (sans se soucier de la deuxième opération si la première est véridique) pour contrôler une affectation. Cette utilisation n'a rien à voir avec le but de l'opérateur. Je ne pense pas qu'il devrait jamais être utilisé.

Je préfère l'opérateur ternaire pour l'initialisation, par exemple,

var title = title?title:'Error';

Cela utilise une opération conditionnelle d'une ligne pour son objectif correct. Il joue toujours à des jeux disgracieux avec véracité mais, c'est Javascript pour vous.

tqwhite
la source