如何缩短我的条件语句

155

我有一个非常长的条件语句,类似于以下内容:

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

我在想是否能将这个表达式/语句重构为更简洁的形式。

你有什么想法吗?


23
你可以将它们放入一个数组中,并使用in吗? - jeremy
2
http://snook.ca/archives/javascript/testing_for_a_v - Muhammad Umer
现在只要有人能够检查哪一个是最快的。 - Muhammad Umer
3
也许会让大家震惊,但是 OP 所拥有的速度绝对是完胜的!!!!!!! 可能是因为浏览器对此进行了很多优化..结果: (1) 如果用 ||. (2) switch 语句. (3) 正则表达式. (4) ~. http://jsperf.com/if-statements-test-techsin - Muhammad Umer
4
你可能正在错误的方向上接近这个问题。在这种情况下,这4种类型有共同点。如果我们将其扩展到更极端的情况,假设我们需要添加10种或100种类型以匹配此条件,那么你可能不会考虑使用此解决方案或其他建议。你看到像这样的一个大if语句,认为它是代码异味,这是一个好迹象。让代码更简洁的最佳方式是,如果你可以编写 if (test.your_common_condition)。在这种情况下,更容易理解,并且更具可扩展性。 - gmacdougall
显示剩余5条评论
15个回答

2

对于非常长的字符串列表,这种方法可以节省一些字符(并不是说我会推荐在实际应用中使用,但它应该有效)。

选择一个你知道在测试中不会出现的字符作为分隔符,将它们全部放入一个长字符串中并进行搜索:

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

如果您的字符串有进一步的限制,您甚至可以省略分隔符...
if ("itemaitembitemcitemd".indexOf(test.type)>=0) {
  // doSomething
}

但在这种情况下,您必须小心防止误报(例如,“embite”将在该版本中匹配)


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


1
“contains” 可能比 “some” 更好的解决方案。 - Dennis
1
不需要使用库来完成这个功能:some是EC5中Array原型上的一个函数。 - KaptajnKold
2
真的,但并非每个人都有EC5支持。另外,我只是真的喜欢underscore。 :) - jcreamer898
如果您已经在使用像underscore这样的库,那么这可能是最简单的方法。否则,仅为了一个函数加载整个库就没有太多意义了。 - Moshe Katz

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
('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;

1

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

  1. 简洁
  2. 易读性

因此,有时候#1可能是最快的,但我会选择#2以便后期易于维护。根据情况,我经常选择Walter答案的变体。

首先,我有一个全局可用的函数作为我的现有库的一部分。

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还要快。


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循环运行,并使用第三部分使循环最终退出。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接