如何缩短我的条件陈述

时间:2013-08-21 00:30:41

标签: javascript if-statement

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

if(test.type == 'itema' || test.type == 'itemb' || test.type == 'itemc' || test.type == 'itemd'){
    // do something.
}

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

关于如何实现这一目标的任何想法?

15 个答案:

答案 0 :(得分:242)

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

switch (test.type) {

  case "itema":
  case "itemb":
  case "itemc":
  case "itemd":
    // do something
}

答案 1 :(得分:240)

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

if ([1, 2, 3, 4].includes(test.type)) {
    // Do something
}

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


~代字号快捷键的简短说明:

  

更新:由于我们现在拥有includes方法,因此再次使用~黑客毫无意义。对于那些有兴趣知道它是如何工作和/或在其他代码中遇到它的人,请保留此处。

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

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

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

这是如何工作的?如果在数组中找到一个项目,indexOf将返回其索引。如果找不到该项,则会返回-1。在没有详细说明的情况下,~bitwise NOT operator,仅0会返回-1

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

重要说明:使用代字号快捷方式似乎有争议,因为有些强烈认为代码不够清晰,应该不惜一切代价避免(看到这个答案的评论)。如果你分享他们的情绪,你应该坚持.indexOf(...) >= 0解决方案。


稍长一点的解释:

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

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

1 :    00000000000000000000000000000001
2 :    00000000000000000000000000000010
3 :    00000000000000000000000000000011
15:    00000000000000000000000000001111

现在这里是相同的数字,但是否定:

-1 :   11111111111111111111111111111111
-2 :   11111111111111111111111111111110
-3 :   11111111111111111111111111111101
-15:   11111111111111111111111111110001

为什么负数这种奇怪的组合?简单。负数只是正数+ 1的倒数;将负数添加到正数应该总是产生0

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

以下是我们将-1添加到+1的方式:

   00000000000000000000000000000001      +1
+  11111111111111111111111111111111      -1
-------------------------------------------
=  00000000000000000000000000000000       0

以下是我们如何将-15添加到+15

   00000000000000000000000000001111      +15
+  11111111111111111111111111110001      -15
--------------------------------------------
=  00000000000000000000000000000000        0

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

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

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

<强> 2's Complement Representation for Signed Integers


现在2补码中的速成课程结束了,你会注意到-1是唯一的二进制表示为1的数字。

使用~按位NOT运算符,给定数字中的所有位都被反转。如果我们从0全部开始,那么让1从反转所有位中恢复的唯一方法就是。

所以,所有这一切都是一种冗长的说法,~n只有在0n时才会返回-1

答案 2 :(得分:62)

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

这比~方法

更快
var x = test.type;
if (x == 'itema' ||
    x == 'itemb' ||
    x == 'itemc' ||
    x == 'itemd') {
    //do something
}

http://jsperf.com/if-statements-test-techsin enter image description here (热门:Chrome,底部设置:Firefox)

结论:

如果可能性很少并且您知道某些更有可能发生的事情比if || switch fall through if(obj[keyval]),和if(obj[keyval])

可能性很多,其中任何一个都可能是最常发生的,换句话说,您无法知道哪一个最有可能发生如果适合的话,你可以从对象查找regex和{{1}}中获得最佳性能。

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

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

答案 3 :(得分:32)

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

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

if (test.type == 'itema' ||
    test.type == 'itemb' ||
    test.type == 'itemc' ||
    test.type == 'itemd') {
    do something.
}

答案 4 :(得分:16)

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

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

答案 5 :(得分:15)

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

如果项目不均匀,那么:

if( /^(itema|itemb|itemc|itemd)$/.test(test.type) ) { /* do something */ }

答案 6 :(得分:10)

优秀的答案,但你可以通过将其中一个包装在一个函数中来使代码更具可读性。

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

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

function CheckIfBusinessRuleIsTrue() 
{
    return (the best solution from previous posts here);
}

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

答案 7 :(得分:4)

您可以将所有答案放入Javascript Set,然后只需在集合上调用.contains()

您仍然需要声明所有内容,但内联呼叫会更短。

类似的东西:

var itemSet = new Set(["itema","itemb","itemc","itemd"]);
if( itemSet.contains( test.type ){}

答案 8 :(得分:2)

我最喜欢的一种方法是使用诸如underscore.js ...

之类的库
var isItem = _.some(['itema','itemb','itemc','itemd'], function(item) {
    return test.type === item;
});

if(isItem) {
    // One of them was true
}

http://underscorejs.org/#some

答案 9 :(得分:2)

我发现的另一种方式或其他方式是......

if ('a' in oc(['a','b','c'])) { //dosomething }

function oc(a)
{
  var o = {};
  for(var i=0;i<a.length;i++)  o[a[i]]='';
  return o;
}

当然,正如您所看到的,这会使事情更进一步,并使它们更容易遵循逻辑。

http://snook.ca/archives/javascript/testing_for_a_v

使用〜&amp;&amp;等运营商|| ((),())~~只有在以后代码中断时才可以。你不会知道从哪里开始。所以可读性很高。

如果你必须你可以缩短它。

('a' in oc(['a','b','c'])) && statement;
('a' in oc(['a','b','c'])) && (statements,statements);
('a' in oc(['a','b','c']))?statement:elseStatement;
('a' in oc(['a','b','c']))?(statements,statements):(elseStatements,elseStatements);

如果你想反向

('a' in oc(['a','b','c'])) || statement;

答案 10 :(得分:2)

只需使用switch语句而不是if语句:

switch (test.type) {

  case "itema":case "itemb":case "itemc":case "itemd":
    // do your process
  case "other cases":...:
    // do other processes
  default:
    // do processes when test.type does not meet your predictions.
}

Switch也比比较if

中的大量条件更快

答案 11 :(得分:2)

对于非常长的字符串列表,这个想法会节省一些字符(不是说我会在现实生活中推荐它,但它应该有用)。

选择一个你知道在test.type中不会出现的字符,将其用作分隔符,将它们全部粘贴到一个长字符串中并搜索:

if ("/itema/itemb/itemc/itemd/".indexOf("/"+test.type+"/")>=0) {
  // doSomething
}

如果你的字符串恰好被进一步限制,你甚至可以省略分隔符......

if ("itemaitembitemcitemd".indexOf(test.type)>=0) {
  // doSomething
}

...但在这种情况下你必须小心误报(例如“embite”会匹配该版本)

答案 12 :(得分:2)

为了便于阅读,请为测试创建一个函数(是的,一行函数):

function isTypeDefined(test) {
    return test.type == 'itema' ||
           test.type == 'itemb' ||
           test.type == 'itemc' ||
           test.type == 'itemd';
}

然后调用它:

…
    if (isTypeDefined(test)) {
…
}
...

答案 13 :(得分:1)

我认为编写这种if条件时有两个目标。

  1. 简洁
  2. 可读性
  3. 因此有时#1可能是最快的,但我会稍后将#2用于轻松维护。根据情况,我会经常选择改变沃尔特的答案。

    首先,我将全局可用功能作为现有库的一部分。

    function isDefined(obj){
      return (typeof(obj) != 'undefined');
    }
    

    然后当我真的想要运行类似于你的if条件时,我会创建一个带有有效值列表的对象:

    var validOptions = {
      "itema":1,
      "itemb":1,
      "itemc":1,
      "itemd":1
    };
    if(isDefined(validOptions[test.type])){
      //do something...
    }
    

    它不像switch / case语句那么快,比其他一些例子更冗长,但我经常在代码中的其他地方重用对象,这非常方便。

    在上面制作的一个jsperf样本上捎带我添加了这个测试和一个比较速度的变化。 http://jsperf.com/if-statements-test-techsin/6我注意到的最有趣的事情是,Firefox中的某些测试组合比Chrome更快。

答案 14 :(得分:1)

这可以通过一个简单的for循环来解决:

test = {};
test.type = 'itema';

for(var i=['itema','itemb','itemc']; i[0]==test.type && [
    (function() {
        // do something
        console.log('matched!');
    })()
]; i.shift());

我们使用for循环的第一部分来初始化你想要匹配的参数,第二部分用来阻止for循环运行,第三部分用来使循环最终退出。