switch case 语句中的表达式
Posted
技术标签:
【中文标题】switch case 语句中的表达式【英文标题】:Expression inside switch case statement 【发布时间】: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
【问题讨论】:
【参考方案1】:switch
块不是这样工作的。 case
用于保存单个值,如果它们等于 switch
行上的值。 if-else
声明会很好地为您服务。
这里是关于switch
块的一些信息。
https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Statements/switch
【讨论】:
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 这个答案还是错的:检查switch(
中的specification — ⟨expr1⟩和⟨expr2⟩都在switch(
⟨ expr1⟩ ) case
⟨expr2⟩ : break;
是表达式。【参考方案2】:
首先,switch
不是这样工作的。您必须为每个case
指定常量,这些常量将与括号中的表达式(在您的情况下为amount
)进行比较。这就是switch
的工作方式,句号。
其次,switch不比几个if
s快
第三,在处理 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,所以让我们多一些创意,以防出现问题,并且,我认为,增加一点可读性。
所以我们不评估每个case
是true
还是false
;我们正在比较 case
的值是否等于我们的 switch
术语。因此,让我们通过在我们的 case
语句中添加一个速记 if
来利用这一点,并如果条件为真则返回我们原来的 switch 项。
我还提供了一个现实世界的示例,您希望有两个“默认值”——一个如果您的术语在正方向上超出您的“重要”范围,另一个如果您是反方向。
关键词:
case (x > 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。
【讨论】:
以上是关于switch case 语句中的表达式的主要内容,如果未能解决你的问题,请参考以下文章