web-dev-qa-db-fra.com

Expression à l'intérieur de l'instruction case switch

J'essaie de créer une instruction switch mais je n'arrive pas à utiliser une expression qui est évaluée (plutôt qu'une chaîne/un entier défini). Je peux facilement le faire avec des déclarations, mais le cas devrait être plus rapide, espérons-le.

J'essaie ce qui suit

function reward(amount) {
    var $reward = $("#reward");
    switch (amount) {
        case (amount >= 7500 && amount < 10000):
            $reward.text("Play Station 3");
            break;
        case (amount >= 10000 && amount < 15000):
            $reward.text("XBOX 360");
            break;
        case (amount >= 15000):
            $reward.text("iMac");
            break;
        default:
            $reward.text("No reward");
            break;
    }
}

Est-ce que je manque quelque chose d'évident ou est-ce que ce n'est pas possible? Google n'a pas été amical dans ce cas.

Toute aide/pointeurs appréciés

M

27
Marko

Tu pourrais toujours faire

switch (true) {
  case (amount >= 7500 && amount < 10000):
    //code
    break;
  case (amount >= 10000 && amount < 15000):
    //code
    break;

  //etc...

Cela fonctionne car true est une constante et le code sous la première instruction case avec une expression évaluée à true sera exécuté.

C'est un peu "difficile" je suppose, mais je ne vois rien de mal à l'utiliser. Une simple déclaration if/else serait probablement plus concise et vous ne craindriez pas les retombées accidentelles. Mais voilà quand même.

97
MooGoo

Ce n'est pas ainsi qu'un bloc switch fonctionne. case est utilisé pour contenir une valeur unique qui, si elles sont égales à la valeur de la ligne switch. Les déclarations if-else vous serviront bien.

Voici quelques informations sur le bloc switch.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch

10
Daniel A. White

La fonction switch (true) de @ MooGoo vous donnera une erreur Weird condition dans jsLint , nous allons donc un peu plus de créativité au cas où cela poserait un problème et, je pense, améliorer la lisibilité.

Nous n'évaluons donc pas si chaque case est true ou false; nous comparons si la valeur de cette case est égale à notre terme switch. Profitons-en donc en jetant un raccourci if dans notre déclaration case et retournons notre terme de commutateur d'origine si la condition est vraie.

J'inclus également une sorte d'exemple du monde réel, où vous voulez avoir deux "valeurs par défaut" - une si votre terme est en dehors de votre plage "importante" dans la direction positive, et une autre si vous êtes dans la négative direction.

Phrase clé: case (x > 0 ? x : null):

"Si mon terme, x, est supérieur à zéro, retourne x pour que x === x et moi prenions la branche de cas."

http://jsfiddle.net/rufwork/upGH6/1/

/*global document*/
/*jslint evil:true*/
var x = 10;

switch (x) {
    case (x > 0 ? x : null):
        document.write('ha ha ha!  I fooled switch AND jsLint!  Muhahahahaha!');
        break;
    case 0:
        document.write('zero is nothing.');
        break;
    case -1:
        document.write('low');
        break;
    case -2:
        document.write('lower');
        break;
    case -3: 
        document.write('lowest I care about');
        break;
    default: // anything lower than -3.
        document.write('TOO LOW!!!! (unless you cheated and didn\'t use an int)');
}
document.write('<br>done.');
9
ruffin

Premièrement, ce n'est pas comme cela que fonctionne switch. Vous devez spécifier des constantes pour chaque case, et ces constantes seront comparées à l'expression entre parenthèses (dans votre cas, amount). C’est ainsi que fonctionne switch, point à point.

Deuxièmement, le commutateur n’est pas plus rapide que plusieurs ifs

Et troisièmement, vous ne devriez pas vous inquiéter des optimisations de performances minuscules lorsque vous utilisez du javascript.

2
Fyodor Soikin

Eh bien, vous pouvez avoir des expressions dans l'instruction case, raison pour laquelle votre commutateur n'est pas une erreur de syntaxe. Mais vous devez comprendre que la clause Case est comparée à l'aide de === (comparaison stricte). Une fois que vous avez compris cela, que la valeur doit correspondre exactement à la valeur d'expression de votre switch(expression), vous pouvez rechercher des expressions dans js.

Les appels de fonction sont des expressions, alors essayons avec eux:

function xbox(amount) { return amount >= 10000 && amount < 15000 && amount; }

function reward(amount) {
  var ps3 = function(amount) { return amount >= 7500 && amount < 10000 && amount; }

  function iMac(amount) { return amount >= 15000 && amount; }

  var $reward = $("#reward");
  switch (amount) {
    case ps3(amount):
      $reward.text("Play Station 3");
      break;
    case xbox(amount):
      $reward.text("XBOX 360");
      break;
    case iMac(amount):
      $reward.text("iMac");
      break;
    default:
      $reward.text("No reward");
      break;
  }
}
reward(8200)// -> Play Station 3
reward(11000)// -> XBOX 360
reward(20000)// -> iMac

Comme vous pouvez le constater, vous pouvez utiliser à la fois des expressions de fonction et des définitions de fonction. Ça n'a pas d'importance. Seulement que l'expression dans la clause case est une expression à évaluer. Ce qui est identique à ce que vous avez fait, sauf que vous n’avez pas renvoyé une valeur identique au montant, mais une valeur vraie ou fausse. Dans mon exemple, je retourne le montant exact si ma condition est vraie et par conséquent déclenche la comparaison.

Voici votre code fixe:

function reward(amount) {
    var $reward = $("#reward");
    switch (amount) {
        case (amount >= 7500 && amount < 10000 && amount):
            $reward.text("Play Station 3");
            break;
        case (amount >= 10000 && amount < 15000 && amount):
            $reward.text("XBOX 360");
            break;
        case (amount >= 15000 && amount):
            $reward.text("iMac");
            break;
        default:
            $reward.text("No reward");
            break;
    }
}

Voici la spécification: https://tc39.github.io/ecma262/#sec-switch-statement Le lien est vers es2016 car il est plus facile à consulter que l'ancien pdf es3 de 1999. Mais a toujours fonctionné de la sorte, mais c’est un fait peu connu.

Je doute toutefois que cela soit plus rapide que les déclarations if. Si vous voulez que votre course soit rapide, alors ne le faites pas touchez le DOM.

1
dotnetCarpenter

Vous pouvez également essayer l'une de mes constructions préférées:

function reward(amount) {
    var $reward = $("#reward");
    $reward.text(
        (amount >= 7500 && amount < 10000) ?    "Play Station 3" :
        (amount >= 10000 && amount < 15000)?    "XBOX 360" :
        (amount >= 15000) ?                     "iMac" :
                                                "No reward"
    );
}
1
robert

Le problème est que l'expression de commutateur ne peut jamais être égale aux expressions de casse, car elle sera évaluée comme étant vraie ou fausse, mais cette expression sera un nombre.

La solution dans laquelle l'expression de commutateur est définie sur true ne fonctionne pas parce que true est une constante, mais parce que l'égalité avec les expressions de casse est réellement possible. 

Ce n'est pas vrai que vous devez spécifier des constantes pour chaque expression de casse. 

Pour confirmer ma réponse, voir Douglas Crockford, Javascript The Good Parts (2008), page 12:

L'instruction switch effectue une branche à plusieurs voies. Elle compare l'expression pour l'égalité avec tous les cas sélectionnés .... Lorsqu'une correspondance exacte est trouvée, les instructions de la clause case correspondante sont exécutées ... Une clause case contient une ou plusieurs expressions de cas. Les expressions de cas ne doivent pas nécessairement être des constantes.

1
Jon Lyles

Mes 2 centimes:

Dans l’idéal, permuter (en principe) devrait s’évaluer sur une branche de cas unique, permettant ainsi d’atteindre les performances O(1) et (autre que de passer en revue les cas) les instructions de cas pouvant être réorganisées de quelque manière que ce soit sans changer la stratégie de branchement du compilateur.

Si des expressions sont utilisées (en supposant que le langage le permette), alors, théoriquement, il peut suivre plus qu'une branche.

Le compilateur (autre que ceux qui peuvent dire intelligemment ce que le développeur essaie de faire) ne sera pas en mesure d'optimiser la stratégie de branchement de manière statique et, idéalement, de perdre ainsi son efficacité.

Exemple:

var x = 6, factors = [];

switch(x){

    case (x%2 == 0): factors.Push(2);
    break;

    case (x%3 == 0): factors.Push(3);
    break;
    ....
 }

{Attendez des commentaires sur un code faible}

Dans l'exemple ci-dessus, le compilateur ne dispose d'aucun moyen pratique d'optimiser statiquement, il ne gagne donc aucun avantage en termes de performances.

La seule partie est que cela "peut" sembler plus propre au développeur mais pourrait en fait être une cause de perturbation en cas de conditions supplémentaires.

0
GNM