web-dev-qa-db-fra.com

Alternative à l'opérateur ternaire imbriqué dans JS

Personnellement, j'adore les opérateurs ternaires et, à mon humble avis, ils rendent les expressions compliquées très faciles à digérer. Prends celui-ci:

  Word = (res.distance === 0) ? 'a'
    : (res.distance === 1 && res.difference > 3) ? 'b'
    : (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) ? 'c'
    : 'd';

Cependant, dans le projet ESLINT, les règles des opérateurs ternaires imbriqués sont interdites. Je dois donc supprimer ce qui précède.

J'essaie de trouver des alternatives à cette approche. Je ne veux vraiment pas en faire une énorme déclaration if/else, mais je ne sais pas s'il existe d'autres options.

19
dthree

À mon goût, un ternaire imbriqué soigneusement structuré bat tous ces ifs et switchs désordonnés

const isFoo = res.distance === 0;
const isBar = res.distance === 1 && res.difference > 3;
const isBaz = res.distance === 2 && res.difference > 5 && String(res.key).length > 5;

const Word =
  isFoo ? 'a' :
  isBar ? 'b' :
  isBaz ? 'c' :
          'd' ;

Vous pouvez écrire une expression de fonction immédiatement appelée pour la rendre un peu plus lisible:

const Word = (() =>  {
  if (res.distance === 0) return 'a';
  if (res.distance === 1 && res.difference > 3) return 'b';
  if (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) return 'c';
  return 'd';
})();

Lien vers repl

2
Yo Wakita

Si toutes vos conditions de vérité évaluent les valeurs de vérité (la valeur entre le point d'interrogation et le point-virgule devient true si contraint de devenir booléen ...), vous pouvez faire en sorte que vos expressions ternaires retournent false en tant qu'expression falsy. Vous pouvez ensuite les chaîner avec l’opérateur au niveau du bit ou (||) pour tester la condition suivante, jusqu’à la dernière où vous aurez renvoyé la valeur par défaut.

Dans l'exemple ci-dessous, le tableau "condsXXX" représente le résultat de l'évaluation des conditions. "conds3rd" simule que la 3ème condition est vraie et "condsNone" simule qu'aucune condition n'est vraie. Dans un code de la vie réelle, vous auriez les conditions "en ligne" dans l'expression d'affectation:

var conds3rd = [false, false, true];
var condsNone = [false, false, false];

var val3rd = (conds3rd[0] ? 1 : false) ||
  (conds3rd[1] ? 2 : false) ||
  (conds3rd[2] ? 3 : 4);

var valNone = (condsNone[0] ? 1 : false) ||
  (condsNone[1] ? 2 : false) ||
  (condsNone[2] ? 3 : 4);

alert(val3rd);
alert(valNone);

Votre exemple pourrait se terminer comme ci-dessous:

Word = ((res.distance === 0) ? 'a' : false) ||
    ((res.distance === 1 && res.difference > 3) ? 'b' : false) ||
    ((res.distance === 2 && res.difference > 5 && String(res.key).length > 5) ? 'c' : 'd';

En passant, je ne pense pas que ce soit un bon code, mais il est tout à fait proche d’utiliser l’opérateur ternaire pur comme vous le souhaiteriez ...

2
Amit
Word = (res.distance === 0) ? 'a'
: (res.distance === 1 && res.difference > 3) ? 'b'
: (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) ? 'c'
: 'd';

C'est une question plus ancienne, mais c'est comme cela que je le ferais ... Je commencerais par le cas par défaut, puis changerais la variable ou le passerai tel que souhaité.

var Word = 'd';
Word = (res.distance === 0) ? 'a' : Word;
Word = (res.distance === 1 && res.difference > 3) ? 'b' : Word
word = (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) ? 'c' : Word;
2
K McCabe

Si vous cherchez à utiliser const avec une expression ternaire imbriquée, vous pouvez remplacer le ternaire par une expression de fonction.

const res = { distance: 1, difference: 5 };

const branch = (condition, ifTrue, ifFalse) => condition?ifTrue:ifFalse;
const Word = branch(
  res.distance === 0,    // if
  'a',                   // then
  branch(                // else
    res.distance === 1 && res.difference > 3,   // if
    'b',                                        // then
    branch(                                     // else
      res.distance === 2 && res.difference > 5,   // if
      'c',                                        // then
      'd'                                         // else
    )
  )
);

console.log(Word);

ou en utilisant des paramètres nommés via la déstructuration ...

const branch2 = function(branch) {
  return branch.if ? branch.then : branch.else;
}

const fizzbuzz = function(num) {
  return branch2({
    if: num % 3 === 0 && num % 5 === 0,
    then: 'fizzbuzz',
    else: branch2({
        if: num % 3 === 0,
        then: 'fizz',
        else: branch2({
          if: num % 5 === 0,
          then: 'buzz',
          else: num
        })
      })
  });
}

console.log(
  [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16].map(
    cv => fizzbuzz(cv)
  )
);

... edit: Il peut être plus clair de le modéliser après le python si l'expression ressemble à ceci:

const res = { distance: 1, difference: 5 };

const maybe = def => ({
  if: expr => {
    if (expr) {
      return { else: () => def };
    } else {
      return { else: els => els };
    }
  }
});
const Word = maybe('a').if(res.distance === 0).else(
  maybe('b').if(res.distance === 1 && res.difference > 3).else(
    maybe('c').if(res.distance === 2 && res.difference > 5).else('d')
  )
);
console.log(Word);

1
Doug Coburn

J'ai fait face à cela trop récemment et une recherche sur Google m'a conduit ici, et je veux partager quelque chose que j'ai découvert récemment à ce sujet:

a && b || c

est presque la même chose que

a ? b : c

tant que b est la vérité. Si b n'est pas la vérité, vous pouvez le contourner en utilisant

!a && c || b

si c est la vérité.

La première expression est évaluée en tant que (a && b) || c car && a plus de priorité que ||.

Si a est vérité, alors a && b serait évalué à b si b était vérité, ainsi l'expression devient b || c qui devient b si c'est vrai, tout comme a ? b : c serait si a était vérité, et si a n'était pas vérité, l'expression serait évaluée c si nécessaire.

En alternant les astuces && et || et les ? et || dans les couches de l'instruction, la règle eslint no-nested-ternary est astucieuse, ce qui est très pratique (bien que je ne recommande pas de le faire à moins qu'il n'y ait pas d'autre issue).

Une démonstration rapide:

true ? false ? true : true ? false : true ? true ? true : false : true : true
// which is interpreted as
true ? (false ? true : (true ? false : (true ? (true ? true : false) : true))) : true
// now with the trick in alternate levels
true ? (false && true || (true ? false : (true && (true ? true : false) || true))) : true
// all of these evaluate to false btw

En fait, j'ai un peu triché en choisissant un exemple où b est toujours la vérité, mais si vous ne faites que définir des chaînes, cela devrait fonctionner correctement, même si '0' est ironiquement la vérité.

0
Ambyjkl

J'ai utilisé une instruction switch (true) pour ces cas. A mon avis, cette syntaxe est légèrement plus élégante que les opérateurs imbriqués if/else

switch (true) {
  case condition === true :
    //do it
    break;
  case otherCondition === true && soOn < 100 :
    // do that
    break;
}
0
ap-o