如何缩短我的条件陈述

Fly*_*Cat 153 javascript if-statement

我有一个很长的条件语句,如下所示:

if(test.type == 'itema' || test.type == 'itemb' || test.type == 'itemc' || test.type == 'itemd'){
    // do something.
}
Run Code Online (Sandbox Code Playgroud)

我想知道我是否可以将这个表达式/语句重构为更简洁的形式.

有关如何实现这一点的任何想法?

Yur*_*ter 242

您可以使用带有fall thru的switch语句:

switch (test.type) {

  case "itema":
  case "itemb":
  case "itemc":
  case "itemd":
    // do something
}
Run Code Online (Sandbox Code Playgroud)

  • @SuryaPratap坠落是有点在这里:) (11认同)
  • 它与if基本相同,数组方法的索引要好得多 (9认同)
  • 令人遗憾的是@kojiro,正确的答案就是这个,但它不可能得到关注,而不是令人敬畏的bitwhise阵列技巧. (6认同)
  • 这个解决方案是Firefox和Safari上最快的解决方案,在Chrome上是第二快的(在原来的`||`之后).请参见http://jsperf.com/if-statements-test-techsin (3认同)
  • 如果你有很多条件,我觉得写一个方法会很糟糕......如果对于一些条件很好,但是对于超过10个,我会选择数组保持代码整洁. (3认同)

Jos*_*ber 240

将您的值放入数组中,并检查您的项目是否在数组中:

if ([1, 2, 3, 4].includes(test.type)) {
    // Do something
}
Run Code Online (Sandbox Code Playgroud)

如果您支持的浏览器没有该Array#includes方法,则可以使用此polyfill.


~波形符快捷键的简短说明:

更新:因为我们现在有了这个includes方法,所以再也不用使用~hack了.对于那些有兴趣知道它是如何工作和/或在其他代码中遇到它的人来说,只需保留它.

而不是检查结果是否indexOf>= 0,有一个很好的小捷径:

if ( ~[1, 2, 3, 4].indexOf(test.type) ) {
    // Do something
}
Run Code Online (Sandbox Code Playgroud)

这是小提琴:http://jsfiddle.net/HYJvK/

这是如何运作的?如果在数组中找到项,则indexOf返回其索引.如果找不到该项目,它将返回-1.没有太多的细节,这~是一个按位NOT运算符,0它只返回-1.

我喜欢使用~快捷方式,因为它比在返回值上进行比较更简洁.我希望JavaScript有一个in_array直接返回布尔值的函数(类似于PHP),但这只是一厢情愿的想法(更新:它现在可以.它被称为includes.见上文).请注意,jQuery inArray虽然共享PHP的方法签名,但实际上模仿了本机indexOf功能(如果索引是您真正想要的,那么在不同情况下这很有用).

重要提示:使用波浪形快捷方式似乎有争议,因为有些人强烈认为代码不够清晰,应该不惜一切代价避免(请参阅本答复的评论).如果你分享他们的情绪,你应该坚持.indexOf(...) >= 0解决方案.


一点点解释:

JavaScript中的整数是有符号的,这意味着最左边的位被保留为符号位; 一个标志,指示该数字是正数还是负数,其中a 1为负数.

以下是32位二进制格式的一些样本正数:

1 :    00000000000000000000000000000001
2 :    00000000000000000000000000000010
3 :    00000000000000000000000000000011
15:    00000000000000000000000000001111
Run Code Online (Sandbox Code Playgroud)

现在这里是相同的数字,但负面:

-1 :   11111111111111111111111111111111
-2 :   11111111111111111111111111111110
-3 :   11111111111111111111111111111101
-15:   11111111111111111111111111110001
Run Code Online (Sandbox Code Playgroud)

为什么这些奇怪的组合为负数?简单.负数只是正数+ 1的倒数; 将负数加到正数应该总是屈服0.

要理解这一点,让我们做一些简单的二进制算术.

下面是我们如何将添加-1+1:

   00000000000000000000000000000001      +1
+  11111111111111111111111111111111      -1
-------------------------------------------
=  00000000000000000000000000000000       0
Run Code Online (Sandbox Code Playgroud)

这里是我们如何将添加-15+15:

   00000000000000000000000000001111      +15
+  11111111111111111111111111110001      -15
--------------------------------------------
=  00000000000000000000000000000000        0
Run Code Online (Sandbox Code Playgroud)

我们如何得到这些结果?通过定期添加,我们在学校教授的方式:从最右边的列开始,然后添加所有行.如果总和大于最大的单位数(以十进制表示9,但是以二进制表示1),我们将余数转移到下一列.

现在,正如您将注意到的,当向正数添加负数时,不是全部0s 的最右侧列将始终具有两个1s,当将它们加在一起时将导致2.二者的二进制表示10,我们将其1带到下一列,并将0结果放在第一列中.左边的所有其他列只有一行带有a 1,所以1从前一列继承的将再次加起来2,然后将继续...这个过程重复直到我们到达最左边的列,其中在1结转已无处可去,所以它溢出和丢失,且我们留下了0所有跨秒.

该系统称为2的补充.你可以在这里阅读更多相关信息:

2对有符号整数的补码表示.


既然2的补码中的速成课程结束了,你会注意到这-1是唯一一个二进制表示1全部的数字.

使用~按位NOT运算符,给定数字中的所有位都被反转.0从反转所有位回来的唯一方法是,如果我们1全都开始.

所以,这一切都是说的啰嗦的方式~n只会返回0如果n-1.

  • -1新程序员看到这样的答案,认为这是一种很酷且可接受的编码方式,然后在5年内我必须维护他们的代码并撕掉我的头发 (65认同)
  • 虽然使用按位运算符肯定是性感的,它是否真的比`!== -1`以任何可能的方式更好?显式布尔逻辑是否比隐式使用零的假设更合适? (59认同)
  • 这个成语在C#,Java或Python等语言中绝对不常见,这些都是我的专业领域.我刚刚在这里询问了一些本地Javascript专家,他们之前从未见过它们.所以它显然不像你声称的那么普遍.**应该总是避免使用更清晰,更常见的`!= -1`.** (23认同)
  • 很好看,但我不喜欢它.乍一看目前还不清楚代码在做什么,这使得它无法维护.我更喜欢"Yuriy Galanter"的回答. (21认同)
  • -1由于在一种语言中不必要的bitfiddling,它首先没有真正指定很多关于位表示的语言.此外,这个答案的大部分内容都在解释这个问题.如果你必须写20段来解释黑客攻击,它真的可以节省任何时间吗? (12认同)
  • @Dennis`~`不是*快捷方式*.它是按位*NOT*运算符 (8认同)
  • @mikeTheLiar,这是代码评论的用途.许多程序员不知道正则表达式,但这并不意味着我应该停止使用它们使代码更简单.我尝试以一种允许我将来理解我所写内容的方式编写代码.对于维护代码的任何其他人,我必须假设使用的语言具有基本级别的能力.如果维护代码的人没有这种能力水平,那么他们的工作就是学习,而不是我的工作就是愚蠢的事情.[我*不是*试图说写一个过于聪明的代码是个好主意](http://tinyurl.com/y97o8yb). (7认同)
  • 为简洁起见,你牺牲了大量的可读性.我希望除了你之外没有人看过这个代码,否则你原来的版本会更优越. (7认同)
  • 提示:如果JavaScript专家不知道a)`indexOf`因缺少存在而返回`-1`和b)`~`运算符做什么,和/或无法理解`〜[...] .indexOf( ...)`在*第一次读*时*,然后**他们不是JavaScript专家**. (7认同)
  • 如果您需要向绝大多数看过它的人解释您的代码,那么您可能想要一些更容易理解的东西. (6认同)
  • @Phil - 虽然我确实认为按位运算符是一种hack,但它是众所周知的,所以它不像代码是不可读的.我真的很喜欢波浪形的简洁,但如果你不喜欢它,不要使用它.我在答案中添加了`-1`检查. (5认同)
  • 这是一个非常有趣的信息,在这么浅薄的问题后,谁知道这样美好的答案. (5认同)
  • @BobFincheimer - 使用按位运算符时,数字*转换*为带符号的32位整数.请参阅[MDN上的这篇文章](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Signed_32-bit_integers):**所有按位运算符的操作数都转换为以big-endian顺序和二进制补码格式签署32位整数.**. (5认同)
  • @MuhammadUmer - 我不明白你的观点.无论它们是什么,都必须枚举这些项目.将它们存储在数组中是枚举它们的最短方法. (4认同)
  • @mikeTheLiar,是和否.`~foo.indexOf(bar)`快捷方式是[非常](http://stackoverflow.com/a/12399125/497418)[常用](http://stackoverflow.com/q/10582286/497418)[方式](http://stackoverflow.com/q/9316612/497418)写`foo.contains(bar)`,就像`foo ||一样 bar`是`foo的常见缩写形式?foo:bar` (4认同)
  • @MuhammadUmar - 不.由于为任何给定的数字只分配了32位,因此最后一位将溢出并永远丢失,导致总和为0.再次阅读我的帖子. (4认同)
  • @MuhammadUmer - 精心制作? (3认同)
  • 我更喜欢用`> = 0`来检查它是否具有更宽松的条件(当文档仅表示返回负值时(可能是`!== - 1`) (3认同)
  • @BlueRaja - 我认为它的方式,如果它们在有能力的程序员中常用(例如使用`a || b`代替'a?a:b`),这样的黑客是可以接受的.由于这个波浪形的黑客是众所周知和使用的,我不认为你必须"撕掉你的头发".我知道这是一个意见问题,所以如果你不喜欢,不要使用它; 这就是我在答案中包含其他方法的原因. (3认同)
  • @ BlueRaja-DannyPflughoeft和所有 - 这项技术非常有名(见[这里](http://www.javascriptturnsmeon.com/the-tilde-operator-in-javascript/)和[这里](http:// viget .COM /启发/ A-快速对 - 的 - 随机JavaScript的提示)).即使是[简单搜索](https://www.google.com/search?q=javascript+tilde+indexof)也可以解释它.**它的偏好是意见问题**.也就是说,由于很多人认为这是一个坏主意,我已经将第一个解决方案还原为使用`> = 0`,并在波浪号解决方案旁边添加了一个大注释.这是我不得不说的最后一点. (3认同)
  • -1,并非所有浏览器都支持indexOf.仅针对一个快捷方式引入浏览器不兼容性并不是一种好习惯. (3认同)
  • 您可能想要详细说明波浪号快捷方式. (2认同)
  • @JosephSilber:JavaScript中保证32位整数的二进制表示形式吗?AFAIK [ECMAScript规范](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf)没有描述它.我担心依赖`〜-1 == false`是不可移植的. (2认同)
  • @ BlueRaja-DannyPflughoeft我同意,我并不认为它在Javascript中很常见,我多年来每天都在使用它.位操作太低,无法轻易想到它. (2认同)
  • 如果你愿意的话,你可以使用它,如果你不愿意的话,就不要使 在阅读他们的代码时尊重他人的选择.不是每个人都能以同样的方式思考.对于某些人来说,某些事情看起来更有条理,更容易.更不用说偏好也会改变加班时间. (2认同)
  • tilde将-1(不在数组中)转换为0(false).这完全不直观,它不会颠倒逻辑.谨防! (2认同)

Muh*_*mer 63

使用科学:你应该做idfah所说的和最快的速度,同时保持代码简短:

这比~方法更快

var x = test.type;
if (x == 'itema' ||
    x == 'itemb' ||
    x == 'itemc' ||
    x == 'itemd') {
    //do something
}
Run Code Online (Sandbox Code Playgroud)

http://jsperf.com/if-statements-test-techsin 在此输入图像描述 (热门:Chrome,底部设置:Firefox)

结论:

如果可能性是少数,你知道,某些是更有可能比你得到最大的性能出去发生if ||,switch fall throughif(obj[keyval]).

如果可能性很多,并且其中任何一个都可能是最常出现的,换句话说,你不可能知道哪一个最有可能发生,而不是你从对象查找获得最大的性能if(obj[keyval]),regex如果这适合.

http://jsperf.com/if-statements-test-techsin/12

如果出现新的东西,我会更新.

  • 如果你真的在这个输入上做了很多循环,它会更快,但是如果你有一个非常大的n("itemX"字符串数)的循环,它会慢很多.我破解了[此代码生成器](https://github.com/kojiromike/misc/blob/master/genSpeedTest.js),您可以使用它来验证(或者可能反驳).如果n很大,`obj ["itemX"]`非常快.基本上,什么是快速取决于上下文.玩得开心. (8认同)
  • So it's the fastest method, but*does it matter*? (3认同)
  • +1一个非常好的帖子!如果我理解正确,`switch case`是最快的方法? (2认同)

idf*_*fah 32

如果要与字符串进行比较并且存在模式,请考虑使用正则表达式.

否则,我怀疑试图缩短它只会混淆你的代码.考虑简单地包裹线条以使其漂亮.

if (test.type == 'itema' ||
    test.type == 'itemb' ||
    test.type == 'itemc' ||
    test.type == 'itemd') {
    do something.
}
Run Code Online (Sandbox Code Playgroud)

  • 这个答案是速度方面的赢家http://jsperf.com/if-statements-test-techsin (4认同)

koj*_*iro 16

var possibilities = {
  "itema": 1,
  "itemb": 1,
  "itemc": 1,
…};
if (test.type in possibilities) { … }
Run Code Online (Sandbox Code Playgroud)

使用对象作为关联数组是很常见的事情,但由于JavaScript没有本机集,因此您也可以将对象用作廉价集.


Mat*_*att 15

if( /^item[a-d]$/.test(test.type) ) { /* do something */ }
Run Code Online (Sandbox Code Playgroud)

或者如果物品不均匀,那么:

if( /^(itema|itemb|itemc|itemd)$/.test(test.type) ) { /* do something */ }
Run Code Online (Sandbox Code Playgroud)

  • "有些人在面对问题时,会想'我知道,我会使用正则表达式'." 现在他们有两个问题." - Jamie Zawinski,1997年 (9认同)
  • @MosheKatz虽然我能理解人们喜欢对这句话嗤之以鼻 - 而且人们肯定会使用正则表达式来表示完全不合适的东西,但这不是其中之一.在OP提供的情况下,这不仅符合标准,而且非常好.正则表达式本质上不是邪恶的,并且匹配具有良好定义的参数的字符串就是它的用途. (5认同)
  • @ Thor84no通常情况下,我会假设提问者实际上并没有尝试与第一种情况下的这样一个人为的例子相匹配,并且真实世界的匹配并不那么简单,在这种情况下我认为RegEx不会做正确的方法.换句话说,如果您的RegEx只是一个以管道字符分隔的选项列表,那么它不会比任何其他建议更具可读性,并且效率可能会大大降低. (3认同)

Fra*_*oey 10

很好的答案,但你可以通过将其中一个包装在一个函数中使代码更具可读性.

如果声明很复杂,当您(或其他人)在几年内阅读代码时,您将通过扫描查找该部分以了解发生的情况.具有此级别业务逻辑的语句将导致您在计算出正在测试的内容时偶然发现几秒钟.像这样的代码,将允许您继续扫描.

if(CheckIfBusinessRuleIsTrue())
{
    //Do Something
}

function CheckIfBusinessRuleIsTrue() 
{
    return (the best solution from previous posts here);
}
Run Code Online (Sandbox Code Playgroud)

明确命名您的函数,以便立即明确您正在测试的内容,并且您的代码将更容易扫描和理解.


归档时间:

查看次数:

19537 次

最近记录:

7 年,1 月 前