关于javascript:switch语句为大于/小于

Switch statement for greater-than/less-than

所以我想使用这样的switch语句:

1
2
3
4
5
6
7
8
switch (scrollLeft) {
  case (<1000):
   //do stuff
   break;
  case (>1000 && <2000):
   //do stuff
   break;
}

现在我知道这些陈述(<1000或(>1000 && <2000)中的任何一个都不起作用(显然是由于不同的原因)。我要求的是最有效的方法。我讨厌使用30个if语句,所以我宁愿使用switch语法。有什么我能做的吗?


当我查看其他答案中的解决方案时,我看到了一些我知道对性能不利的事情。我本来打算把他们放在评论中,但我认为最好是进行基准测试并分享结果。你可以自己测试。下面是我的结果(ymmv),在每个浏览器中进行最快操作后进行标准化(将1.0时间乘以标准化值,得到以毫秒为单位的绝对时间)。

1
2
3
4
5
6
7
8
9
10
11
                    Chrome  Firefox Opera   MSIE    Safari  Node
-------------------------------------------------------------------
1.0 time               37ms    73ms    68ms   184ms    73ms    21ms
if-immediate            1.0     1.0     1.0     2.6     1.0     1.0
if-indirect             1.2     1.8     3.3     3.8     2.6     1.0
switch-immediate        2.0     1.1     2.0     1.0     2.8     1.3
switch-range           38.1    10.6     2.6     7.3    20.9    10.4
switch-range2          31.9     8.3     2.0     4.5     9.5     6.9
switch-indirect-array  35.2     9.6     4.2     5.5    10.7     8.6
array-linear-switch     3.6     4.1     4.5    10.0     4.7     2.7
array-binary-switch     7.8     6.7     9.5    16.0    15.0     4.9

测试在Windows7 32位上执行的位置,包括以下版本:Chrome21.0.1180.89m、Firefox 15.0、Opera 12.02、MSIE 9.0.8112、Safari 5.1.7。节点在Linux 64位设备上运行,因为node.js for windows的计时器分辨率是10毫秒而不是1毫秒。

如果立即

这是所有测试环境中最快的,除了…鼓鼓囊囊!(惊喜,惊喜)。这是建议的实现方法。

1
2
3
4
if (val < 1000) { /*do something */ } else
if (val < 2000) { /*do something */ } else
...
if (val < 30000) { /*do something */ } else

如果间接

这是switch-indirect-array的变体,但使用if语句,在几乎所有测试环境中的性能都比switch-indirect-array快得多。

1
2
3
4
5
6
7
values=[
   1000,  2000, ... 30000
];
if (val < values[0]) { /* do something */ } else
if (val < values[1]) { /* do something */ } else
...
if (val < values[29]) { /* do something */ } else

立即切换

这在所有测试环境中都非常快,实际上是MSIE中最快的。它在您可以进行计算以获取索引时工作。

1
2
3
4
5
6
switch (Math.floor(val/1000)) {
  case 0: /* do something */ break;
  case 1: /* do something */ break;
  ...
  case 29: /* do something */ break;
}

开关范围

这比所有测试环境中的最快速度慢6到40倍,除了对于歌剧来说,要花大约一倍半的时间。因为发动机太慢了必须对每种情况对值进行两次比较。令人惊讶的是,与Chrome中最快的操作相比,Chrome完成这项操作需要将近40倍的时间,而MSIE只需要6倍的时间。但实际时间差只有74ms,而msie的时间差只有1337ms。.

1
2
3
4
5
6
switch (true) {
  case (0 <= val &&  val < 1000): /* do something */ break;
  case (1000 <= val &&  val < 2000): /* do something */ break;
  ...
  case (29000 <= val &&  val < 30000): /* do something */ break;
}

开关测距2

这是switch-range的变体,但每个案例只有一个比较,因此速度更快,但除歌剧外速度仍然很慢。case语句的顺序很重要,因为引擎将按照源代码顺序ecmascript262:5 12.11测试每个案例。

1
2
3
4
5
6
switch (true) {
  case (val < 1000): /* do something */ break;
  case (val < 2000): /* do something */ break;
  ...
  case (val < 30000): /* do something */ break;
}

切换间接数组

在这个变量中,范围存储在一个数组中。这在所有测试环境中都很慢,在Chrome中非常慢。

1
2
3
4
5
6
7
8
values=[1000,  2000 ... 29000, 30000];

switch(true) {
  case (val < values[0]): /* do something */ break;
  case (val < values[1]): /* do something */ break;
  ...
  case (val < values[29]): /* do something */ break;
}

数组线性搜索

这是对数组中的值进行线性搜索和切换的组合具有固定值的语句。人们可能希望使用它的原因是直到运行时才知道值。它在每个测试环境中都很慢,而且在MSIE中所用的时间几乎是10倍。

1
2
3
4
5
6
7
8
9
10
11
12
values=[1000,  2000 ... 29000, 30000];

for (sidx=0, slen=values.length; sidx < slen; ++sidx) {
  if (val < values[sidx]) break;
}

switch (sidx) {
  case 0: /* do something */ break;
  case 1: /* do something */ break;
  ...
  case 29: /* do something */ break;
}

阵列二进制开关

这是array-linear-switch的变体,但使用二进制搜索。不幸的是,它比线性搜索慢。我不知道这是我的实现还是线性搜索更优化。也可能是关键空间太小。

1
2
3
4
5
6
7
8
9
10
11
12
13
values=[0, 1000,  2000 ... 29000, 30000];

while(range) {
  range = Math.floor( (smax - smin) / 2 );
  sidx = smin + range;
  if ( val < values[sidx] ) { smax = sidx; } else { smin = sidx; }
}

switch (sidx) {
  case 0: /* do something */ break;
  ...
  case 29: /* do something */ break;
}

结论

如果性能很重要,请使用带即时值的if语句或switch


另一种选择:

1
2
3
4
5
6
7
8
9
10
var scrollleft = 1000;
switch (true)
{
    case (scrollleft > 1000):
      alert('gt');
      break;
    case (scrollleft <= 1000):
      alert('lt');
      break;
}

演示:http://jsfiddle.net/uwyzr/


1
2
3
4
5
6
7
8
switch (Math.floor(scrollLeft/1000)) {
  case 0: // (<1000)
   //do stuff
   break;
  case 1: // (>=1000 && <2000)
   //do stuff;
   break;
}

只有当你有固定的步骤…

编辑:由于这个解决方案一直在提高投票率,我必须建议莫弗罗的解决方案是一个更好的方法


可以使用条件和与条件对应的函数创建自定义对象

1
2
3
var rules = [{ lowerLimit: 0,    upperLimit: 1000, action: function1 },
             { lowerLimit: 1000, upperLimit: 2000, action: function2 },
             { lowerLimit: 2000, upperLimit: 3000, action: function3 }];

为这些情况下要执行的操作定义函数(定义函数1、函数2等)

"评估"规则

1
2
3
4
5
6
7
8
9
10
11
function applyRules(scrollLeft)
{
   for(var i=0; i>rules.length; i++)
   {
       var oneRule = rules[i];
       if(scrollLeft > oneRule.lowerLimit && scrollLeft < oneRule.upperLimit)
       {
          oneRule.action();
       }
   }
}

注释

I hate using 30 if statements

很多时候,如果语句更易于阅读和维护。我建议只有当你有很多的条件和未来很多增长的可能性的时候,以上。

更新正如@brad在评论中指出的,如果条件是相互排斥的(一次只能有一个条件是真的),那么检查上限就足够了:

1
if(scrollLeft < oneRule.upperLimit)

前提是条件是按升序定义的(例如,先是最低的,0 to 1000,然后是1000 to 2000)


未经测试,不确定这是否有效,但为什么不在之前做一些if statements,为switch statement设置变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var small, big;

if(scrollLeft < 1000){
    //add some token to the page
    //call it small
}


switch (//reference token/) {
  case (small):
   //do stuff
   break;
  case (big):
   //do stuff;
   break;
}

你到底在江户做什么?

你可以做如下的事情:

1
2
3
4
(scrollLeft < 1000) ? //do stuff
: (scrollLeft > 1000 && scrollLeft < 2000) ? //do stuff
: (scrollLeft > 2000) ? //do stuff
: //etc.


I hate using 30 if statements

我最近也遇到过同样的情况,我就是这样解决的:

之前:

1
2
3
4
5
6
7
8
9
10
11
if(wind_speed >= 18) {
    scale = 5;
} else if(wind_speed >= 12) {
    scale = 4;
} else if(wind_speed >= 9) {
    scale = 3;
} else if(wind_speed >= 6) {
    scale = 2;
} else if(wind_speed >= 4) {
    scale = 1;
}

后:

1
2
var scales = [[4, 1], [6, 2], [9, 3], [12, 4], [18, 5]];
scales.forEach(function(el){if(wind_speed > el[0]) scale = el[1]});

如果您设置"1、2、3、4、5",那么它可能更简单:

1
2
var scales = [4, 6, 9, 12, 18];
scales.forEach(function(el){if(wind_speed >= el) scale++});


在我的例子中(颜色编码百分比,没有性能关键),我很快写下了:

1
2
3
4
5
6
7
8
function findColor(progress) {
    const thresholds = [30, 60];
    const colors = ["#90B451","#F9A92F","#90B451"];

    return colors.find((col, index) => {
        return index >= thresholds.length || progress < thresholds[index];
    });
}

更新已接受的答案(尚不能评论)。从16年12月1日起,使用chrome中的demo jfiddle,switch immediate是最快的解决方案。

结果:时间分辨率:1.33

1
2
3
4
5
6
7
8
   25ms"if-immediate" 150878146
   29ms"if-indirect" 150878146
   24ms"switch-immediate" 150878146
   128ms"switch-range" 150878146
   45ms"switch-range2" 150878146
   47ms"switch-indirect-array" 150878146
   43ms"array-linear-switch" 150878146
   72ms"array-binary-switch" 150878146

完成了

1
2
3
4
5
6
7
8
 1.04 (   25ms) if-immediate
 1.21 (   29ms) if-indirect
 1.00 (   24ms) switch-immediate
 5.33 (  128ms) switch-range
 1.88 (   45ms) switch-range2
 1.96 (   47ms) switch-indirect-array
 1.79 (   43ms) array-linear-switch
 3.00 (   72ms) array-binary-switch


这是另一种选择:

1
2
3
4
5
6
7
8
9
10
11
     switch (true) {
         case (value > 100):
             //do stuff
             break;
         case (value <= 100)&&(value > 75):
             //do stuff
             break;
         case (value < 50):
            //do stuff
             break;
     }