简体   繁体   English

switch case 语句中的表达式

[英]Expression inside switch case statement

I'm trying to create a switch statement but I can't seem to be able to use an expression that gets evaluated (rather than a set string/integer).我正在尝试创建一个 switch 语句,但我似乎无法使用一个被评估的表达式(而不是一个设置的字符串/整数)。 I can easily do this with if statements but case should hopefully be faster.我可以使用 if 语句轻松地做到这一点,但 case 应该会更快。

I'm trying the following我正在尝试以下

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

Am i missing something obvious or is this not possible?我是否遗漏了一些明显的东西或者这是不可能的? Google hasn't been friendly in this case.在这种情况下,谷歌并不友好。

Any help/pointers appreciated任何帮助/指针表示赞赏

M

amount is a number, but the expressions in the case clauses only evaluate to booleans; amount是一个数字,但case子句中的表达式仅计算为布尔值; the values will never match.这些值永远不会匹配。

You could always do你总是可以做

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

It works because the value being matched is now the boolean true , so the code under the first case clause with an expression that evaluates to true will be executed.它之所以有效,是因为被匹配的值现在是布尔值true ,因此将执行第一个case子句下的代码,其表达式的计算结果为true

It's kinda “tricky”, I guess, but I see nothing wrong with using it.我猜这有点“棘手”,但我认为使用它没有任何问题。 A simple ifelse statement would probably be more concise, and you'd not have to worry about accidental fall-through.一个简单的ifelse语句可能会更简洁,而且您不必担心意外掉线。 But there it is anyway.但无论如何它就在那里。

@MooGoo's switch (true) will give you a Weird condition error in jsLint , so let's get a little more creative in case that's an issue, and, I think, increase readability a touch. @MooGoo 的switch (true)会给你一个Weird condition错误,所以如果这是一个问题,让我们更有创意,而且,我认为,增加一点可读性。

So we're not evaluating if each case is true or false ;所以我们不评估每个casetrue还是false we're comparing if that case 's value is equal to our switch term.我们正在比较case的值是否等于我们的switch项。 So let's take advantage of that by throwing a shorthand if into our case statement and return our original switch term if the condition's true .因此,让我们通过在我们的case语句中添加一个速记if来利用这一点,如果条件为 true 则返回我们原来的 switch 项

I'm also including a sort of real world example, where you want to have two "defaults" -- one if your term is outside of your "important" range in the positive direction, and another in case you're in the negative direction.我还包括一个现实世界的例子,你希望有两个“默认值”——一个如果你的术语在正方向上超出了你的“重要”范围,另一个是在你处于负方向的情况下方向。

Key phrase: case (x > 0 ? x : null):关键词: case (x > 0 ? x : null):

"If my term, x , is greater than zero, return x so that x === x and I take the case branch." “如果我的术语x大于零,则返回x以便x === x并且我采用 case 分支。”

http://jsfiddle.net/rufwork/upGH6/1/ 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.');

Quick reply to @Sv443 :快速回复@Sv443

Do notice that the default: switch says, " unless you cheated and didn't use an int " and that short circuiting requires x === x when you return x .请注意default: switch 说,“除非你作弊并且没有使用 int ”并且当你返回 x 时短路需要x === x x

But your point is a useful reminder that NaN is the only case where short circuiting can't apply.但是你的观点是一个有用的提醒, NaN唯一不能应用短路的情况。

That is, x must == x to short circuit in switch and, as MDN tells us, " NaN, and only NaN, will compare unequal to itself " (double or triple = ).也就是说, x必须== x才能在switch中短路,并且正如 MDN 告诉我们的那样,“ NaN,并且只有 NaN,将与自身比较不相等”(双倍三倍= )。

That also means that switching on a NaN value (and only a NaN value) will always hit default in ANY switch because you can't match its value.这也意味着打开NaN值(并且只有NaN值)将始终ANY switch中达到default ,因为您无法匹配其值。

Here's the full quote from MDN :这是来自MDN的完整报价:

NaN compares unequal (via ==, !=, ===, and !==) to any other value -- including to another NaN value. NaN 将不相等(通过 ==、!=、=== 和 !==)与任何其他值进行比较——包括另一个 NaN 值。 Use Number.isNaN() or isNaN() to most clearly determine whether a value is NaN.使用Number.isNaN()isNaN()最清楚地确定一个值是否为 NaN。 Or perform a self-comparison: NaN, and only NaN, will compare unequal to itself.或者执行自我比较:NaN,并且只有 NaN,将与自身比较不相等。

You could change the default logic to check what you have:您可以更改default逻辑以检查您拥有的内容:

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

Or you even could go full hipster like MDN suggests (but please don't ;^D):或者你甚至可以像 MDN 建议的那样去完全时髦(但请不要 ;^D):

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

That is not how a switch block works.这不是switch块的工作方式。 The case is used to hold a single value that if they are equal to the value on the switch line. case用于保存单个值,如果它们等于switch线上的值。 if-else statements will serve you well. if-else语句会很好地为您服务。

Here is some information about the switch block.这是有关switch块的一些信息。

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

Well, you can have expressions in case statement which is why your switch is not a syntax error.好吧,您可以在case语句中使用表达式,这就是您的 switch 不是语法错误的原因。 But you have to understand that the Case Clause is compared using === (strict comparison).但是你必须明白, Case Clause是使用 === 进行比较的(严格比较)。 Once you understand this, that the value must match exactly with the expression value in your switch(expression) you can shop around for expressions in js.一旦你理解了这一点,该值必须与你的switch(expression)中的表达式值完全匹配,你可以在 js 中到处寻找表达式。

Function calls are expressions, so let's try with them:函数调用是表达式,所以让我们尝试使用它们:

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

As you can see, you can both use function expressions and function definitions.如您所见,您既可以使用函数表达式,也可以使用函数定义。 It doesn't matter.没关系。 Only that the expression in the case clause is an expression to evaluate.只有 case 子句中的表达式是要计算的表达式。 Which is the same as you did, only you did not return a value that was the same as the amount but rather a true or false value.这与您所做的相同,只是您没有返回与金额相同的值,而是返回真值或假值。 In my example I return the exact amount if my condition is true, hence trigger the comparison to match.在我的示例中,如果我的条件为真,我会返回确切的金额,从而触发比较匹配。

Here is your fixed code:这是您的固定代码:

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

Here is the specification: https://tc39.github.io/ecma262/#sec-switch-statement The link is to es2016 because it's easier to lookup than the old es3 pdf from 1999. But it has always worked like this, but it is a little known fact.这是规范: https ://tc39.github.io/ecma262/#sec-switch-statement 链接是 es2016,因为它比 1999 年的旧 es3 pdf 更容易查找。但它一直是这样工作的,但是这是一个鲜为人知的事实。

I however doubt that this is faster than if statements.然而,我怀疑这是否比if语句更快。 If you want your run to run fast, then do not touch the DOM.如果你想让你的跑步跑得更快,那么就不要碰 DOM。

You could also try one of my favorite constructions:你也可以试试我最喜欢的结构之一:

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

My 2 cents:我的 2 美分:

Ideally switch (as a principle) should evaluate to a single case branch , thereby achieving O(1) performance and (other than fall through cases) the case statements can be reordered in any way without changing the compiler branching strategy.理想情况下, switch (作为原则)应该评估为单个 case branch ,从而实现 O(1) 性能,并且(除了失败案例)可以以任何方式对 case 语句重新排序,而无需更改编译器分支策略。

If expressions are used (assuming the language allows it), then theoretically, it can follow more than branch.如果使用表达式(假设语言允许),那么理论上,它可以跟随的不仅仅是分支。

The compiler (other than those which can intelligently say what the developer is trying to do) will not be able to optimize the branching strategy statically and ideally thus losing its effectiveness.编译器(除了那些可以智能地说明开发人员正在尝试做什么的编译器)将无法静态和理想地优化分支策略,从而失去其有效性。

Example:例子:

var x = 6, factors = [];

switch(x){

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

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

{Expect comments on poor code} {期待对糟糕代码的评论}

In the above example, there is no practical way for the compiler to statically optimize, thus gains no performance benefit over if else.在上面的示例中,编译器没有实用的静态优化方法,因此与 if else 相比没有性能优势。

The only part is that, it "may" look cleaner to the developer but could in-effect be cause for disruption in case of additional conditions.唯一的部分是,它“可能”对开发人员来说看起来更干净,但实际上可能会在出现其他情况时导致中断。

Firstly, that's not how switch works.首先,这不是switch的工作方式。 You have to specify constants for each case , and those constants will be compared to the expression in parentheses (in your case, amount ).您必须为每个case指定常量,这些常量将与括号中的表达式(在您的情况下为amount )进行比较。 That is how switch works, period.这就是switch的工作原理,期间。

Secondly, switch is not faster than several if s其次,switch 不比几个if

And thirdly, you shouldn't really worry about miniscule performance optimizations when you're dealing with javascript.第三,在处理 javascript 时,您不应该真正担心微不足道的性能优化。

The problem is the switch expression cannot ever equal the case expressions, because the case expression will evaluate to true or false, but the switch expression will be a number.问题是 switch 表达式永远不能等于 case 表达式,因为 case 表达式将评估为真或假,但 switch 表达式将是一个数字。

The solution where the switch expression is set to true works not because true is a constant but because equality with the case expressions is actually possible. switch 表达式设置为 true 的解决方案不是因为 true 是一个常量,而是因为与 case 表达式相等实际上是可能的。

It's not true that you have to specify constants for each case expression.您必须为每个 case 表达式指定常量是不正确的。

To back up my answer, refer to Douglas Crockford, Javascript The Good Parts (2008), page 12:要支持我的答案,请参阅 Douglas Crockford,Javascript The Good Parts (2008),第 12 页:

The switch statement performs a multiway branch. switch 语句执行多路分支。 It compares the expression for equality with all the selected cases.... When an exact match is found, the statements of the matching case clause are executed... A case clause contains one or more case expressions.它将表达式的相等性与所有选定的情况进行比较......当找到完全匹配时,执行匹配的 case 子句的语句...... case 子句包含一个或多个 case 表达式。 The case expressions need not be constants. case 表达式不必是常量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM