【问题标题】:Expression inside switch case statementswitch case 语句中的表达式
【发布时间】:2011-03-28 16:32:36
【问题描述】:

我正在尝试创建一个 switch 语句,但我似乎无法使用被评估的表达式(而不是设置的字符串/整数)。我可以使用 if 语句轻松做到这一点,但希望 case 更快。

我正在尝试以下方法

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

【问题讨论】:

    标签: javascript switch-statement case


    【解决方案1】:

    switch 块不是这样工作的。 case 用于保存单个值,如果它们等于 switch 行上的值。 if-else 声明会很好地为您服务。

    这里是关于switch 块的一些信息。

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

    【讨论】:

    【解决方案2】:

    首先,switch 不是这样工作的。您必须为每个case 指定常量,这些常量将与括号中的表达式(在您的情况下为amount)进行比较。这就是switch 的工作方式,句号。

    其次,switch不比几个ifs快

    第三,在处理 javascript 时,您不应该真正担心微不足道的性能优化。

    【讨论】:

    • 好吧,担心性能总是更好。当你必须做一些消耗性能的事情时,它会给你空间。
    • “您必须为每种情况指定常量” - 不,您不需要。使用常量是使用switch 的最常见方式,但您可以在每个case 中指定任何表达式,带或不带变量或函数调用,值就是要比较的值。
    • 第一段错误:检查specification — switch(中的⟨expr1⟩⟨expr2⟩都有⟨ expr1⟩ ){ case ⟨expr2⟩ : break; } 是表达式。其他两段更适合作为评论,而不是答案。
    【解决方案3】:

    你总是可以的

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

    之所以有效,是因为true 是一个常量,因此将执行第一个case 语句下的表达式计算结果为真的代码。

    我猜这有点“棘手”,但我认为使用它没有任何问题。一个简单的if/else 语句可能会更简洁,您不必担心意外掉线。但无论如何,它就在那里。

    【讨论】:

    • 这比丹尼尔斯的“答案”更好。有一个轻微的警告:在导致 case true 的表达式之前的所有表达式也将被评估。小心点。
    • 是的,这是可行的,因为您总是可以将 switch 函数想象成一个跳转表,它只需要匹配并检索一个值。这与 if/else 语句不同,因为所有 if 都需要实际评估。在上面,您要求您的开关评估与匹配。这就是 switch case 更快的原因。
    • @Vontei - 使用 if/else if/else 结构时,它们不会被 all 评估,仅在特定条件为真之前依次评估它们,即评估 case 表达式时会发生同样的事情。
    【解决方案4】:

    问题是 switch 表达式永远不能等于 case 表达式,因为 case 表达式将计算结果为真或假,但 switch 表达式将是一个数字。

    switch 表达式设置为 true 的解决方案不是因为 true 是一个常量,而是因为与 case 表达式相等实际上是可能的。

    不必为每个 case 表达式指定常量。

    要支持我的回答,请参阅 Douglas Crockford,Javascript The Good Parts (2008),第 12 页:

    switch 语句执行多路分支。它将表达式的相等性与所有选定的情况进行比较...。找到完全匹配时,执行匹配的 case 子句的语句... case 子句包含一个或多个 case 表达式。 case 表达式不必是常量。

    【讨论】:

    • 可以补充一点,案例块评估是按照源代码的顺序执行的。从上到下。
    【解决方案5】:

    @MooGoo 的switch (true) 会给你一个Weird condition error in jsLint,所以让我们多一些创意,以防出现问题,并且,我认为,增加一点可读性。

    所以我们不评估每个casetrue 还是false;我们正在比较 case 的值是否等于我们的 switch 术语。因此,让我们通过在我们的 case 语句中添加一个速记 if 来利用这一点,并如果条件为真则返回我们原来的 switch 项

    我还提供了一个现实世界的示例,您希望有两个“默认值”——一个如果您的术语在正方向上超出您的“重要”范围,另一个如果您是反方向。

    关键词: case (x &gt; 0 ? x : null):

    “如果我的任期 x 大于零,则返回 x 以便 x === x 和我进行案例分支。”

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

    快速回复to @Sv443

    请注意default: 开关说:“除非你作弊并且没有使用 int”,并且当你返回 x 时短路需要 x === x

    但您的观点是一个有用的提醒,NaN唯一不能应用短路的情况。

    也就是说,x 必须 == x 短路 switch 并且,正如 MDN 告诉我们的那样,“NaN, and only NaN, will compare unequal to itself”(双 =)。

    这也意味着打开NaN 值(并且 NaN 值)将总是ANY中点击default strong> switch 因为你无法匹配它的值。

    这是来自MDN的完整报价:

    NaN 将不相等(通过 ==、!=、=== 和 !==)与任何其他值(包括另一个 NaN 值)进行比较。使用Number.isNaN()isNaN() 最清楚地确定一个值是否为NaN。或者执行自我比较:NaN,并且只有 NaN,将与自身进行比较。

    您可以更改 default 逻辑以检查您拥有的内容:

    isNaN(x) ? document.write ('nan') : document.write('TOO LOW!!!! ...)');

    或者你甚至可以像 MDN 建议的那样去完全时髦(但请不要;^D):

    x !== x ? document.write ('nan') : document.write('TOO LOW!!!! ...)');

    【讨论】:

    • 这可能会愚弄 JSLint,但比 JSLint 一开始抱怨的事情更奇怪,更难阅读。如果您有意识地决定在 OP 想要和 MooGoo 解释的情况下使用带有表达式的 switch,那么您就不必担心特定的 JSLint 警告。
    • @nnnnnn 好吧,我想说switch (true) 完全是反模式,因为MooGoo 本质上是在重新创建if... else if... else。我的主要观点是,这个问题确实让我想到了开关范围的一个可以说是实际的用途——如果你发现自己处于基本上需要两个 (+?) 默认值的switch 范式中。很清楚您可以在case 中使用表达式,返回switch 的参数值,并在该语句处强制调用。但听起来你正在投票给@Daniel 和@FyodorSoikin 的“这不是 switch 的工作原理”的答案,我真的无法争辩 ;)
    • 请注意,这在 x = NaN 时不起作用,因为在内部 JS 可能会进行相等性检查,这对于 NaN 常量是不可能的(它需要使用 Number.isNaN() 进行检查,它不这样做)
    • @Sv443 已在答案更新中解决。在这种情况下,NaN 实际上是证明(嗯,是唯一的例外)规则的例外。
    • 感谢您编辑这个 8 岁的答案 :)
    【解决方案6】:

    你也可以试试我最喜欢的一种结构:

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

    【讨论】:

    • 如果您反向评估,您是否还需要检查金额是否低于数字?
    • 我想这当然会阻止获得更大奖励的人更快地获得他们;)
    • 嵌套三元运算符常常令人害怕和完全不鼓励。因此最好避免使用它们,除非它们比替代结构更简单、明显且更易于维护。我更喜欢按任何顺序工作的测试。无论您选择如何编写它们,这里的简单性和可维护性都胜过效率。
    【解决方案7】:

    我的 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;
        ....
     }
    

    {在糟糕的代码上期望 cmets}

    在上面的示例中,编译器没有实用的静态优化方法,因此不会比 if else 获得性能优势。

    唯一的部分是,它“可能”对开发人员来说看起来更干净,但实际上可能会在出现其他情况时导致中断。

    【讨论】:

      【解决方案8】:

      好吧,您可以在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。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-01-01
        • 1970-01-01
        • 2013-05-08
        • 1970-01-01
        • 1970-01-01
        • 2013-09-24
        相关资源
        最近更新 更多