繁体   English   中英

如何缩短我的条件陈述

[英]How to shorten my conditional statements

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

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

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

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

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

switch (test.type) {

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

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

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

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


在简要解释~波浪号快捷方式:

更新:既然我们现在有了includes方法,那么使用~ hack就没有意义了。 对于那些有兴趣知道它是如何工作和/或在其他代码中遇到它的人来说,只需保留它。

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

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

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

这是如何运作的? 如果在数组中找到一个项, indexOf将返回其索引。 如果找不到该项,则返回-1 没有得到太多的细节,在~按位NOT运算符 ,它会返回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秒,当它们一起添加时将导致2 两个是的二进制表示10 ,我们进行了1到下一列,并把一个0的结果中的第一列。 左边的所有其他列只有一行1 ,所以从前一列结转的1将再次加起来2 ,然后将继续...这个过程重复直到我们到达最左边列,其中1将被带走,无处可去,所以它会溢出并丢失,我们只剩下0秒。

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

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


既然2的补码中的速成课程结束了,你会发现-1是唯一一个二进制表示为1的数字。

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

所以,这一切都是说的一口长气路~n只会返回0 ,如果n-1

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

这是比速度更快~方法

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

您仍然必须声明所有内容,但内联呼叫将更短。

就像是:

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

我最喜欢的方法之一是使用诸如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

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

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;

只需使用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比较大量条件更快

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

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

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

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

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

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

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

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

然后叫它:

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

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

  1. 简短
  2. 可读性

因此有时候#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更快。

这可以通过一个简单的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循环运行,第三部分用来使循环最终退出。

暂无
暂无

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

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