web-dev-qa-db-ja.com

switch caseステートメント内の式

Switchステートメントを作成しようとしていますが、(文字列/整数のセットではなく)評価される式を使用できないようです。 ifステートメントを使用して簡単にこれを行うことができますが、できればケースの方が速くなるはずです。

私は以下を試しています

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;
    }
}

明らかな何かを見逃していますか、これは不可能ですか?この場合、Googleは友好的ではありません。

任意のヘルプ/ポインタを高く評価

[〜#〜] m [〜#〜]

34
Marko

いつでもできる

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

  //etc...

trueは定数であるため機能します。したがって、trueと評価される式を持つ最初のcaseステートメントの下のコードが実行されます。

ちょっと「つまらない」と思いますが、使用しても何も問題はありません。シンプルな if/elseステートメントはおそらくより簡潔であり、偶発的なフォールスルーを心配する必要はありません。しかし、とにかくあります。

109
MooGoo

@MooGooの switch (true) はjsLintで _Weird condition_エラーを返します ですので、問題が発生した場合に備えてもう少し創造的になりましょう。タッチ。

したがって、各casetrueまたはfalseであるかどうかは評価していません。 caseの値がswitch項と等しいかどうかを比較しています。 ifcaseステートメントに省略して、条件がtrueの場合に元の切り替え項を返す

また、2つの「デフォルト」が必要な実世界の例を示します。1つは用語が正の方向で「重要な」範囲外にある場合、もう1つは負の場合です。方向。

キーフレーズ:case (x > 0 ? x : null):

「私の用語xがゼロより大きい場合、xを返すので、_x === x_になり、case分岐を取ります。」

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.');
_
11
ruffin

それはswitchブロックの仕組みではありません。 caseは、switch行の値と等しい場合に単一の値を保持するために使用されます。 if-elseステートメントが役立ちます。

switchブロックに関する情報を次に示します。

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

10
Daniel A. White

まず、それはswitchの仕組みではありません。各caseに定数を指定する必要があり、それらの定数は括弧内の式と比較されます(この場合、amount)。それがswitchの仕組みです。

第二に、切り替えは複数のifsより高速ではありません

そして第三に、javascriptを扱っている場合、ごくわずかなパフォーマンスの最適化について心配するべきではありません。

3
Fyodor Soikin

私のお気に入りの構造のいずれかを試すこともできます:

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"
    );
}
2
robert

caseステートメントに式を含めることができます。これが、スイッチが構文エラーではない理由です。ただし、Case Clauseは===(厳密な比較)を使用して比較されることを理解する必要があります。これを理解したら、値はswitch(expression)の式の値と正確に一致する必要があるため、jsの式を探し回ることができます。

関数呼び出しは式なので、試してみましょう。

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

ご覧のとおり、関数式と関数定義の両方を使用できます。関係ありません。 case句の式が評価する式であることのみ。これはあなたと同じですが、量と同じ値を返さず、真または偽の値を返しただけです。私の例では、条件が真である場合に正確な量を返すため、一致する比較をトリガーします。

固定コードは次のとおりです。

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;
    }
}

仕様は次のとおりです。 https://tc39.github.io/ecma262/#sec-switch-statement リンクはes2016へのものです。1999年の古いes3 pdfよりも検索が簡単だからです。しかし、常にこのように機能していましたが、それはほとんど知られていない事実です。

ただし、これはifステートメントよりも高速であるとは思いません。実行を高速で実行したい場合は、しないでくださいDOMをタッチします。

1
dotnetCarpenter

問題は、case式がtrueまたはfalseに評価されるが、switch式は数値になるため、switch式がcase式と等しくならないことです。

Switch式がtrueに設定されているソリューションは、trueが定数であるためではなく、case式との等価性が実際に可能であるために機能します。

各case式に定数を指定する必要があるのは事実ではありません。

私の答えをバックアップするには、Douglas Crockford、Javascript The Good Parts(2008)、12ページを参照してください。

Switchステートメントは、多方向ブランチを実行します。式が選択されたすべてのケースと等しいかどうかを比較します。完全一致が見つかると、一致するcase節のステートメントが実行されます... case節には1つ以上のcase式が含まれます。ケース式は定数である必要はありません。

1
Jon Lyles

私の2セント:

理想的には、(原則として)switchは単一のcaseブランチに評価する必要があり、それによりO(1)パフォーマンスを達成し、ケースをフォールスルーする場合を除き)caseステートメントを変更せずに任意の順序に並べ替えることができますコンパイラーの分岐戦略。

式が使用されている場合(言語で許可されている場合)、理論的には、分岐よりも後に続くことができます。

コンパイラー(開発者がやろうとしていることを賢く言うことができるものを除く)は、分岐戦略を静的に、そして理想的には最適化できず、そのためその効果を失います。

例:

var x = 6, factors = [];

switch(x){

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

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

{悪いコードに関するコメントを期待する}

上記の例では、コンパイラーが静的に最適化する実用的な方法はないため、他の場合よりもパフォーマンス上の利点はありません。

唯一の部分は、開発者にとっては「きれい」に見えるかもしれませんが、追加の条件の場合に実際に混乱の原因になる可能性があるということです。

0
GNM